Batch sending allows you to send multiple emails in a single API request, which is more efficient than individual sends for bulk operations.
When to Use Batch Sending
Sending notifications to multiple users about the same event
Welcome email campaigns
Shipping notifications for multiple orders
Weekly digest emails
Any scenario with 10+ emails to send
Limits and Considerations
Limit
Value
Max emails per batch
100
Max request size
10 MB
Rate limit
1,000 emails/minute
Batch Response Handling
The batch send response provides detailed results:
interface BatchSendResult { successful: number; // Count of successfully queued emails failed: number; // Count of failed emails results: { email: string; id?: string; // Message ID if successful status: 'queued' | 'failed'; error?: string; // Error message if failed }[]; failures: { email: string; reason: string; }[];}
Handling Partial Failures
Always check for partial failures in batch sends:
const { data, error } = await client.emails.sendBatch({ emails });if (error) { // Complete failure - no emails were processed console.error('Batch request failed:', error.message); return;}// Check for partial failuresif (data.failed > 0) { console.log(`${data.failed} emails failed out of ${data.successful + data.failed}`); for (const failure of data.failures) { // Log for retry or investigation await logFailedEmail(failure.email, failure.reason); }}
Retry Strategy for Failures
Implement exponential backoff for transient failures:
async function sendWithRetry( emails: EmailPayload[], maxRetries = 3): Promise<BatchSendResult> { let lastError: Error | null = null; for (let attempt = 0; attempt < maxRetries; attempt++) { const { data, error } = await client.emails.sendBatch({ emails }); if (!error) { return data; } // Check if error is retryable if (error.code === 'RATE_LIMITED' || error.code === 'SERVICE_UNAVAILABLE') { const delay = Math.pow(2, attempt) * 1000; // 1s, 2s, 4s console.log(`Attempt ${attempt + 1} failed, retrying in ${delay}ms...`); await new Promise((resolve) => setTimeout(resolve, delay)); lastError = new Error(error.message); } else { // Non-retryable error throw new Error(error.message); } } throw lastError || new Error('Max retries exceeded');}
Performance Tips
1. Use Templates for Repeated Content
When sending similar emails to many recipients, use server-side templates to reduce payload size:
// Instead of sending full HTML for each email...const emails = recipients.map(r => ({ to: r.email, templateId: 'welcome-email', // Much smaller payload templateData: { name: r.name },}));
2. Process in Parallel with Limits
For very large sends, process batches in parallel but limit concurrency: