Examples
Typescript
Python
- Python Integration Overview
- Examples
Javascript
- JavaScript Overview
- Examples
Go
- Go Integration Overview
- Examples
PHP
- PHP Integration Overview
- Examples
cURL
Examples
Next.js Integration
Using Shoutbox with Next.js (App Router and Pages Router)
Next.js Integration
Learn how to integrate Shoutbox with Next.js using both the App Router and Pages Router approaches.
Installation
Copy
npm install shoutboxnet
App Router Integration
API Route Handler (Route Handlers)
Copy
// app/api/send-email/route.ts
import Shoutbox from "shoutboxnet";
export async function POST(request: Request) {
try {
const shoutbox = new Shoutbox({
apiKey: process.env.SHOUTBOX_API_KEY
});
const { to, subject, html } = await request.json();
const result = await shoutbox.sendEmail({
from: "[email protected]",
to,
subject,
html,
});
return Response.json({ success: true, result });
} catch (error) {
return Response.json(
{ success: false, error: error.message },
{ status: 500 }
);
}
}
Server Component Usage
Copy
// app/contact/page.tsx
import Shoutbox from "shoutboxnet";
async function ContactPage() {
async function sendEmail(formData: FormData) {
'use server';
const shoutbox = new Shoutbox({
apiKey: process.env.SHOUTBOX_API_KEY
});
try {
await shoutbox.sendEmail({
from: "[email protected]",
to: formData.get('email') as string,
subject: "Contact Form Submission",
html: formData.get('message') as string,
});
} catch (error) {
console.error('Failed to send email:', error);
throw new Error('Failed to send email');
}
}
return (
<form action={sendEmail}>
<input type="email" name="email" required />
<textarea name="message" required></textarea>
<button type="submit">Send</button>
</form>
);
}
export default ContactPage;
Client Component Usage
Copy
// app/components/EmailForm.tsx
'use client';
import { useState } from 'react';
export default function EmailForm() {
const [status, setStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle');
async function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
event.preventDefault();
setStatus('loading');
const formData = new FormData(event.currentTarget);
try {
const response = await fetch('/api/send-email', {
method: 'POST',
body: JSON.stringify({
to: formData.get('email'),
subject: 'Contact Form',
html: formData.get('message'),
}),
headers: {
'Content-Type': 'application/json',
},
});
if (!response.ok) throw new Error('Failed to send email');
setStatus('success');
} catch (error) {
console.error('Error sending email:', error);
setStatus('error');
}
}
return (
<form onSubmit={handleSubmit}>
<input type="email" name="email" required />
<textarea name="message" required></textarea>
<button type="submit" disabled={status === 'loading'}>
{status === 'loading' ? 'Sending...' : 'Send'}
</button>
{status === 'success' && <p>Email sent successfully!</p>}
{status === 'error' && <p>Failed to send email. Please try again.</p>}
</form>
);
}
Pages Router Integration
API Route
Copy
// pages/api/send-email.ts
import type { NextApiRequest, NextApiResponse } from 'next';
import Shoutbox from "shoutboxnet";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
if (req.method !== 'POST') {
return res.status(405).json({ message: 'Method not allowed' });
}
try {
const shoutbox = new Shoutbox({
apiKey: process.env.SHOUTBOX_API_KEY
});
const { to, subject, html } = req.body;
const result = await shoutbox.sendEmail({
from: "[email protected]",
to,
subject,
html,
});
res.status(200).json({ success: true, result });
} catch (error) {
res.status(500).json({ success: false, error: error.message });
}
}
Page Component Usage
Copy
// pages/contact.tsx
import { useState } from 'react';
import type { NextPage } from 'next';
const ContactPage: NextPage = () => {
const [status, setStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle');
async function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
event.preventDefault();
setStatus('loading');
const formData = new FormData(event.currentTarget);
try {
const response = await fetch('/api/send-email', {
method: 'POST',
body: JSON.stringify({
to: formData.get('email'),
subject: 'Contact Form',
html: formData.get('message'),
}),
headers: {
'Content-Type': 'application/json',
},
});
if (!response.ok) throw new Error('Failed to send email');
setStatus('success');
} catch (error) {
console.error('Error sending email:', error);
setStatus('error');
}
}
return (
<div>
<h1>Contact Us</h1>
<form onSubmit={handleSubmit}>
<input type="email" name="email" required />
<textarea name="message" required></textarea>
<button type="submit" disabled={status === 'loading'}>
{status === 'loading' ? 'Sending...' : 'Send'}
</button>
{status === 'success' && <p>Email sent successfully!</p>}
{status === 'error' && <p>Failed to send email. Please try again.</p>}
</form>
</div>
);
};
export default ContactPage;
Environment Variables
Create a .env.local
file in your project root:
Copy
SHOUTBOX_API_KEY=your_api_key_here
Best Practices
Security
- Always keep your API key in environment variables
- Validate email inputs on both client and server
- Implement rate limiting for your API routes
- Use appropriate CORS settings
- Validate request bodies
Error Handling
Copy
// Reusable error handler
const handleEmailError = (error: unknown) => {
if (error instanceof ShoutboxError) {
console.error('Shoutbox API Error:', {
message: error.message,
statusCode: error.statusCode,
code: error.code,
});
// Handle specific error codes
switch (error.code) {
case 'rate_limit_exceeded':
return 'Too many requests. Please try again later.';
case 'invalid_recipient':
return 'Invalid email address provided.';
default:
return 'An error occurred while sending the email.';
}
}
return 'An unexpected error occurred.';
};
Rate Limiting
Copy
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { rateLimit } from './lib/rate-limit';
export async function middleware(request: NextRequest) {
if (request.nextUrl.pathname.startsWith('/api/send-email')) {
const ip = request.ip ?? '127.0.0.1';
const { success } = await rateLimit(ip);
if (!success) {
return NextResponse.json(
{ error: 'Too many requests' },
{ status: 429 }
);
}
}
return NextResponse.next();
}
TypeScript Types
Copy
// types/email.ts
export interface EmailFormData {
to: string;
subject: string;
html: string;
}
export interface EmailResponse {
success: boolean;
result?: any;
error?: string;
}
Testing
Copy
// __tests__/api/send-email.test.ts
import { createMocks } from 'node-mocks-http';
import handler from '../../pages/api/send-email';
jest.mock('shoutboxnet', () => {
return jest.fn().mockImplementation(() => ({
sendEmail: jest.fn().mockResolvedValue({ success: true }),
}));
});
describe('/api/send-email', () => {
it('sends email successfully', async () => {
const { req, res } = createMocks({
method: 'POST',
body: {
to: '[email protected]',
subject: 'Test',
html: '<p>Test content</p>',
},
});
await handler(req, res);
expect(res._getStatusCode()).toBe(200);
expect(JSON.parse(res._getData())).toEqual(
expect.objectContaining({
success: true,
})
);
});
});
Assistant
Responses are generated using AI and may contain mistakes.