fastify-xemail
sendPersonalizedBulk
Send different email content to each recipient using Promise.allSettled — partial failures are reported, not thrown.
sendPersonalizedBulk
Send different email content to each recipient. Uses Promise.allSettled internally — individual delivery failures are captured in the result array rather than thrown, so a failure for one recipient does not abort the rest.
Signature
fastify.xEmail.sendPersonalizedBulk(
messages: PersonalizedMessage[]
): Promise<PersonalizedResult[]>
interface PersonalizedMessage {
to: string;
subject: string;
html: string;
text?: string;
}
interface PersonalizedResult {
success: boolean;
to: string;
statusCode?: number; // present on success
error?: string; // present on failure
}
Params
| Name | Type | Required | Description |
|---|---|---|---|
messages | PersonalizedMessage[] | Yes | Non-empty array of per-recipient message objects. |
Returns
Promise<PersonalizedResult[]> — One result object per input message in the same order.
| Property | Type | Description |
|---|---|---|
success | boolean | true if the individual send succeeded. |
to | string | The recipient email address. |
statusCode | number | HTTP status from SendGrid (on success). |
error | string | Error message (on failure). |
Throws
[xEmail] 'messages' must be a non-empty array for sendPersonalizedBulk().— empty or non-array input.
Individual send failures are not thrown — they appear as { success: false, to, error } entries in the result array.
Examples
Basic — send personalized welcome emails
fastify.post("/users/bulk-welcome", async (request) => {
const users = await db.users.findByIds(request.body.userIds);
const messages = users.map((user) => ({
to: user.email,
subject: `Welcome, ${user.firstName}!`,
html: `<p>Hi ${user.firstName}, your account is ready. <a href="${user.activationUrl}">Activate now</a>.</p>`,
}));
const results = await fastify.xEmail.sendPersonalizedBulk(messages);
const failed = results.filter((r) => !r.success);
if (failed.length > 0) {
fastify.log.warn({ failed }, "Some bulk emails failed to send");
}
return { sent: results.filter((r) => r.success).length, failed: failed.length };
});
Realistic — subscription renewal reminders with error tracking
fastify.post("/subscriptions/send-renewal-reminders", async (request) => {
const expiring = await db.subscriptions.getExpiringInDays(7);
const messages = expiring.map((sub) => ({
to: sub.userEmail,
subject: "Your subscription expires soon",
html: `
<p>Hi ${sub.userName},</p>
<p>Your ${sub.planName} subscription expires on ${sub.expiresAt}.</p>
<p><a href="https://app.example.com/billing/renew?sub=${sub.id}">Renew now</a></p>
`,
}));
const results = await fastify.xEmail.sendPersonalizedBulk(messages);
const failedEmails = results
.filter((r) => !r.success)
.map((r) => ({ email: r.to, reason: r.error }));
await db.emailLog.record({ type: "renewal_reminder", results, failedEmails });
return {
total: results.length,
sent: results.filter((r) => r.success).length,
failed: failedEmails,
};
});
See Also
- send-bulk — Same content to all recipients in a single API call
- send-template — Dynamic template email for a single recipient
AI Context
package: "@xenterprises/fastify-xemail"
method: fastify.xEmail.sendPersonalizedBulk(recipients, options?)
use-when: Send different content to each recipient concurrently using Promise.allSettled — partial failures don't abort the batch
params: recipients (array of {to, subject, html, ...}), options
returns: Promise<Array<{ status, recipient, error? }>>
