Guides
Bulk Sending
Send to thousands of recipients efficiently using the batch endpoint and campaigns.
Sendr has two approaches for sending at scale:
| Approach | Best for | Max per call |
|---|---|---|
| Batch endpoint | Transactional bulk (order updates, notifications) | 100 emails |
| Campaigns | Marketing broadcasts to audiences | Unlimited (via audience) |
Batch endpoint
The /v1/emails/batch endpoint accepts up to 100 emails per request and queues them atomically. All emails in a batch share a default from, subject, and template_id, with per-email overrides.
Basic batch
import { Sendr } from "sendr";
const sendr = new Sendr(process.env.SENDR_API_KEY!);
// Build your list of recipients
const users = [
{ email: "alice@example.com", name: "Alice", orderId: "ORD-001" },
{ email: "bob@example.com", name: "Bob", orderId: "ORD-002" },
// ... up to 100
];
const { data } = await sendr.emails.sendBatch({
from: "orders@acme.com",
subject: "Your order has shipped",
emails: users.map(user => ({
to: user.email,
html: `<p>Hi ${user.name}, order ${user.orderId} has shipped!</p>`,
})),
});
console.log(`Queued ${data.length} emails`);
Large lists: chunk into batches
function chunk<T>(array: T[], size: number): T[][] {
const chunks: T[][] = [];
for (let i = 0; i < array.length; i += size) {
chunks.push(array.slice(i, i + size));
}
return chunks;
}
async function sendToAllUsers(users: User[]) {
const batches = chunk(users, 100); // Max 100 per batch
const results: string[] = [];
for (const batch of batches) {
const { data } = await sendr.emails.sendBatch({
from: "hello@acme.com",
emails: batch.map(user => ({
to: user.email,
html: `<p>Hi ${user.name}!</p>`,
})),
});
results.push(...data.map(e => e.id));
// Brief pause to avoid hitting rate limits
await new Promise(resolve => setTimeout(resolve, 200));
}
return results;
}
Batch with templates
Use template_id for a shared template and variables for per-email substitution:
await sendr.emails.sendBatch({
from: "hello@acme.com",
template_id: "tmpl_abc123",
emails: users.map(user => ({
to: user.email,
variables: {
name: user.name,
plan: user.plan,
expiry: user.expiresAt,
},
})),
});
Campaigns
For marketing broadcasts to large audiences, use campaigns. Unlike the batch endpoint, campaigns:
- Target an entire audience (contact list) rather than individual addresses
- Handle unsubscribes automatically via
List-Unsubscribeheaders - Can be scheduled in advance
- Provide per-campaign analytics
Campaign workflow
// 1. Create an audience
const audience = await sendr.audiences.create({
name: "Pro Plan Users",
});
// 2. Add contacts to the audience
await sendr.contacts.bulkImport([
{ email: "alice@example.com", first_name: "Alice" },
{ email: "bob@example.com", first_name: "Bob" },
// ...thousands more
]);
// 3. Create and schedule the campaign
const campaign = await sendr.campaigns.create({
name: "March Feature Announcement",
subject: "New features in March",
from: "Newsletter <news@acme.com>",
audience_id: audience.id,
html: `
<h1>Here's what's new in March</h1>
<p>We shipped three major features this month...</p>
`,
unsubscribe_url: "https://acme.com/unsubscribe",
scheduled_at: "2025-03-15T09:00:00Z",
});
console.log(campaign.status); // "scheduled"
// 4. Check stats after sending
const stats = await sendr.campaigns.getStats(campaign.id);
console.log(`Delivered: ${stats.delivered} / ${stats.total}`);
console.log(`Open rate: ${((stats.opened / stats.delivered) * 100).toFixed(1)}%`);
Cancelling a campaign
// Cancel before it starts sending
await sendr.campaigns.cancel(campaign.id);
You cannot cancel a campaign once it has started sending.
Plan limits summary
| Feature | Free | Pro | Business | Enterprise |
|---|---|---|---|---|
| Monthly emails | 3,000 | 50,000 | 200,000 | Unlimited |
| Marketing emails/month | 0 | 10,000 | 50,000 | Unlimited |
| Campaigns | 3 | 25 | Unlimited | Unlimited |
| Audiences | 3 | 25 | Unlimited | Unlimited |
| Contacts | 500 | 10,000 | 100,000 | Unlimited |
Free plan does not support marketing emails or campaigns. Upgrade to Pro or higher.
Deliverability tips for bulk sends
- Warm up new domains gradually — start with a few hundred emails/day and increase over 2 weeks
- Verify your audience — remove hard bounces and inactive addresses before large sends
- Use suppression lists — Sendr automatically suppresses hard bounces; check your suppression list before importing
- Segment your audience — engaged subscribers have higher open rates, which improves sender reputation
- Include a real unsubscribe link — required by CAN-SPAM and GDPR, improves deliverability
- Send at consistent times — ISPs look for consistent patterns from legitimate senders