Prerequisites
To get the most out of this guide, you’ll need to:- Create a SendPost Account
- React 18+
- A backend API endpoint (Next.js, Express, etc.) or direct API calls
- A Sub-Account API Key from your SendPost dashboard
You can find your API keys in your SendPost Dashboard. Make sure to use your Sub-Account API Key for sending emails.
Security Note: Never expose your SendPost API key in client-side React code. Always use a backend API endpoint to send emails. The examples below show both approaches, but prefer the backend approach for production.
1. Install Dependencies
npm
npm install axios
# Optional: if using SendPost SDK directly (not recommended for production)
npm install sendpost-js-sdk
2. Create Email Service Hook
Createhooks/useEmail.js:
JavaScript
import { useState } from 'react';
import axios from 'axios';
const API_BASE_URL = process.env.REACT_APP_API_URL || 'http://localhost:3000/api';
export function useEmail() {
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const [success, setSuccess] = useState(false);
const sendEmail = async (emailData) => {
setLoading(true);
setError(null);
setSuccess(false);
try {
const response = await axios.post(`${API_BASE_URL}/send-email`, emailData);
setSuccess(true);
return { success: true, data: response.data };
} catch (err) {
const errorMessage = err.response?.data?.error || err.message || 'Failed to send email';
setError(errorMessage);
return { success: false, error: errorMessage };
} finally {
setLoading(false);
}
};
const sendWelcomeEmail = async ({ email, firstName }) => {
return sendEmail({
to: email,
subject: 'Welcome!',
htmlBody: `
<h1>Welcome, ${firstName}!</h1>
<p>Thank you for joining us.</p>
<p><a href="{{unsubscribe}}">Unsubscribe</a></p>
`,
groups: ['welcome'],
});
};
const sendPasswordReset = async ({ email, resetToken, firstName }) => {
const resetUrl = `${window.location.origin}/reset-password?token=${resetToken}`;
return sendEmail({
to: email,
subject: 'Reset Your Password',
htmlBody: `
<h2>Hello ${firstName},</h2>
<p>Click the link below to reset your password:</p>
<p><a href="${resetUrl}">Reset Password</a></p>
<p>This link will expire in 1 hour.</p>
`,
groups: ['password-reset'],
});
};
return {
sendEmail,
sendWelcomeEmail,
sendPasswordReset,
loading,
error,
success,
};
}
3. Contact Form Component
Createcomponents/ContactForm.jsx:
JavaScript
import React, { useState } from 'react';
import { useEmail } from '../hooks/useEmail';
export default function ContactForm() {
const { sendEmail, loading, error, success } = useEmail();
const [formData, setFormData] = useState({
name: '',
email: '',
message: '',
});
const handleSubmit = async (e) => {
e.preventDefault();
const result = await sendEmail({
to: 'contact@yourdomain.com',
subject: `Contact from ${formData.name}`,
htmlBody: `
<h2>New Contact Form Submission</h2>
<p><strong>Name:</strong> ${formData.name}</p>
<p><strong>Email:</strong> ${formData.email}</p>
<p><strong>Message:</strong></p>
<p>${formData.message.replace(/\n/g, '<br>')}</p>
`,
textBody: `
New Contact Form Submission
Name: ${formData.name}
Email: ${formData.email}
Message: ${formData.message}
`,
});
if (result.success) {
setFormData({ name: '', email: '', message: '' });
}
};
const handleChange = (e) => {
setFormData({
...formData,
[e.target.name]: e.target.value,
});
};
return (
<form onSubmit={handleSubmit} className="space-y-4 max-w-md mx-auto">
<div>
<label htmlFor="name" className="block text-sm font-medium mb-1">
Name
</label>
<input
type="text"
id="name"
name="name"
value={formData.name}
onChange={handleChange}
required
className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-[#5750EC] focus:border-transparent"
/>
</div>
<div>
<label htmlFor="email" className="block text-sm font-medium mb-1">
Email
</label>
<input
type="email"
id="email"
name="email"
value={formData.email}
onChange={handleChange}
required
className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-[#5750EC] focus:border-transparent"
/>
</div>
<div>
<label htmlFor="message" className="block text-sm font-medium mb-1">
Message
</label>
<textarea
id="message"
name="message"
value={formData.message}
onChange={handleChange}
required
rows={5}
className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-[#5750EC] focus:border-transparent"
/>
</div>
<button
type="submit"
disabled={loading}
className="w-full px-6 py-2 bg-[#5750EC] text-white rounded-md hover:bg-[#4640D9] disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
>
{loading ? 'Sending...' : 'Send Message'}
</button>
{error && (
<div className="p-3 bg-red-50 border border-red-200 rounded-md text-red-700 text-sm">
{error}
</div>
)}
{success && (
<div className="p-3 bg-green-50 border border-green-200 rounded-md text-green-700 text-sm">
Message sent successfully!
</div>
)}
</form>
);
}
4. Welcome Email on User Registration
Createcomponents/RegistrationForm.jsx:
JavaScript
import React, { useState } from 'react';
import { useEmail } from '../hooks/useEmail';
export default function RegistrationForm() {
const { sendWelcomeEmail, loading, error, success } = useEmail();
const [formData, setFormData] = useState({
firstName: '',
lastName: '',
email: '',
password: '',
});
const handleSubmit = async (e) => {
e.preventDefault();
// First, register the user (your registration logic here)
try {
// Example: await registerUser(formData);
// Then send welcome email
const result = await sendWelcomeEmail({
email: formData.email,
firstName: formData.firstName,
});
if (result.success) {
// Handle successful registration
console.log('User registered and welcome email sent!');
}
} catch (err) {
console.error('Registration error:', err);
}
};
return (
<form onSubmit={handleSubmit} className="space-y-4">
{/* Form fields */}
<button type="submit" disabled={loading}>
{loading ? 'Registering...' : 'Register'}
</button>
{error && <div className="text-red-600">{error}</div>}
{success && <div className="text-green-600">Registration successful!</div>}
</form>
);
}
5. Password Reset Flow
Createcomponents/PasswordResetRequest.jsx:
JavaScript
import React, { useState } from 'react';
import { useEmail } from '../hooks/useEmail';
export default function PasswordResetRequest() {
const { sendPasswordReset, loading, error, success } = useEmail();
const [email, setEmail] = useState('');
const handleSubmit = async (e) => {
e.preventDefault();
// Generate reset token (your backend should handle this)
const resetToken = await generateResetToken(email);
const result = await sendPasswordReset({
email,
resetToken,
firstName: 'User', // You might want to fetch this from your backend
});
if (result.success) {
// Show success message
}
};
return (
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label htmlFor="email" className="block text-sm font-medium mb-1">
Email Address
</label>
<input
type="email"
id="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
className="w-full px-4 py-2 border border-gray-300 rounded-md"
/>
</div>
<button
type="submit"
disabled={loading}
className="w-full px-6 py-2 bg-[#5750EC] text-white rounded-md"
>
{loading ? 'Sending...' : 'Send Reset Link'}
</button>
{error && (
<div className="p-3 bg-red-50 border border-red-200 rounded-md text-red-700">
{error}
</div>
)}
{success && (
<div className="p-3 bg-green-50 border border-green-200 rounded-md text-green-700">
Password reset link sent to your email!
</div>
)}
</form>
);
}
6. Using Context for Email Service
Createcontext/EmailContext.jsx:
JavaScript
import React, { createContext, useContext } from 'react';
import { useEmail } from '../hooks/useEmail';
const EmailContext = createContext(null);
export function EmailProvider({ children }) {
const emailService = useEmail();
return (
<EmailContext.Provider value={emailService}>
{children}
</EmailContext.Provider>
);
}
export function useEmailContext() {
const context = useContext(EmailContext);
if (!context) {
throw new Error('useEmailContext must be used within EmailProvider');
}
return context;
}
JavaScript
import { EmailProvider } from './context/EmailContext';
function App() {
return (
<EmailProvider>
{/* Your app components */}
</EmailProvider>
);
}
7. Direct API Integration (Not Recommended for Production)
If you must use SendPost SDK directly in React (not recommended), createservices/sendpostClient.js:
JavaScript
import sendpost from 'sendpost-js-sdk';
const emailApi = new sendpost.EmailApi();
const API_KEY = process.env.REACT_APP_SENDPOST_API_KEY; // ⚠️ Not secure!
export async function sendEmailDirect(emailData) {
try {
const emailMessage = new sendpost.EmailMessage();
emailMessage.from = { email: 'hello@playwithsendpost.io' };
emailMessage.to = [{ email: emailData.to }];
emailMessage.subject = emailData.subject;
emailMessage.htmlBody = emailData.htmlBody;
emailMessage.textBody = emailData.textBody;
const response = await emailApi.sendEmail(API_KEY, { emailMessage });
return { success: true, messageId: response.messageId };
} catch (error) {
return { success: false, error: error.message };
}
}
Never expose your API key in client-side code! This example is for demonstration only. Always use a backend API endpoint in production.
8. Environment Variables
Create.env file:
REACT_APP_API_URL=http://localhost:3000/api
# DO NOT add SENDPOST_API_KEY here - use backend only!
9. Error Handling Best Practices
Createutils/emailErrorHandler.js:
JavaScript
export function handleEmailError(error) {
if (error.response) {
// Server responded with error
switch (error.response.status) {
case 400:
return 'Invalid email data. Please check your input.';
case 401:
return 'Authentication failed. Please check your API key.';
case 429:
return 'Too many requests. Please try again later.';
case 500:
return 'Server error. Please try again later.';
default:
return error.response.data?.error || 'An error occurred';
}
} else if (error.request) {
// Request made but no response
return 'Network error. Please check your connection.';
} else {
// Something else happened
return error.message || 'An unexpected error occurred';
}
}
JavaScript
import { handleEmailError } from '../utils/emailErrorHandler';
// In your sendEmail function:
catch (err) {
const errorMessage = handleEmailError(err);
setError(errorMessage);
return { success: false, error: errorMessage };
}
Make sure your sender email domain is verified in your SendPost account before sending emails.
10. Next Steps
Explore more examples and use cases:React Documentation
Learn more about React framework
SendPost JavaScript SDK
View the official SDK package on npm
Personalization Guide
Learn how to personalize emails with Handlebars templates