Sending Emails
For a first message, start with EmailParams, then inspect the response. Add templates, batches, or optional fields only when the workflow needs them. Optional features depend on provider capabilities.
The EmailParams Object
The Send function accepts an EmailParams object. Only to and subject are required -- all other fields are optional.
import { Send } from "@antelopejs/interface-email";
const response = await Send({
to: "[email protected]",
subject: "Welcome aboard",
html: "<h1>Welcome!</h1><p>Thanks for joining.</p>",
text: "Welcome! Thanks for joining.",
});
if (!response.success) {
throw new Error(
response.error?.message ?? "The provider did not accept the email",
);
}
console.log(response.status); // Acceptance is not proof of inbox delivery.
This example uses the configured default sender. Handle rejected promises at your application boundary as well as unsuccessful responses. See Email Response for optional fields and retry precautions.
Required Fields
| Field | Type | Description |
|---|---|---|
to | EmailAddress | EmailAddress[] | One or more recipients |
subject | string | The email subject line |
Content Fields
Provide at least one of text or html, even though the TypeScript type makes both optional. Including both gives readers a plain-text alternative to HTML.
| Field | Type | Description |
|---|---|---|
text | string | Plain text body |
html | string | HTML body |
Address Fields
| Field | Type | Description |
|---|---|---|
from | EmailAddress | Sender address (uses provider default if omitted) |
replyTo | EmailAddress | EmailAddress[] | Reply-to address(es) |
cc | EmailAddress | EmailAddress[] | CC recipients |
bcc | EmailAddress | EmailAddress[] | BCC recipients |
Threading Fields
Use these fields to place an email within an existing thread:
| Field | Type | Description |
|---|---|---|
messageId | string | Custom Message-ID header |
inReplyTo | string | Message-ID of the email being replied to |
references | string | string[] | Message-IDs of the thread |
import { Send } from "@antelopejs/interface-email";
await Send({
to: "[email protected]",
subject: "Re: Project update",
text: "Thanks for the update!",
inReplyTo: "<[email protected]>",
references: ["<[email protected]>"],
});
Email Priority
The priority field requests a priority from providers that support it. It does not guarantee faster delivery. Check features.priority on the awaited provider capabilities before relying on this option.
| Value | Description |
|---|---|
"high" | Request high priority for an urgent message |
"normal" | Standard delivery priority (default) |
"low" | Non-urgent emails such as newsletters |
import { Send } from "@antelopejs/interface-email";
await Send({
to: "[email protected]",
subject: "Server Alert",
text: "CPU usage exceeded 95%.",
priority: "high",
});
Tracking Options
The tracking field configures open and click tracking through the TrackingOptions interface.
| Field | Type | Description |
|---|---|---|
opens | boolean | Track when the recipient opens the email |
clicks | boolean | Track when the recipient clicks links |
trackingDomain | string | Custom domain for tracking URLs |
disabled | boolean | Disable all tracking |
import { Send } from "@antelopejs/interface-email";
await Send({
to: "[email protected]",
subject: "Monthly Report",
html: "<p>Your report is ready. <a href='https://app.example.com/reports'>View it here</a>.</p>",
tracking: {
opens: true,
clicks: true,
trackingDomain: "track.example.com",
},
});
Schedule Options
The schedule field delays email delivery to a specified time using the ScheduleOptions interface.
| Field | Type | Description |
|---|---|---|
sendAt | Date | string | When to send the email (ISO 8601 string or Date object) |
timezone | string | IANA timezone identifier (e.g., "Europe/Paris") |
import { Send } from "@antelopejs/interface-email";
await Send({
to: "[email protected]",
subject: "Monday Standup Reminder",
text: "Standup in 15 minutes.",
schedule: {
sendAt: new Date("2027-04-05T06:45:00Z"),
timezone: "Europe/Paris",
},
});
Note: Check
(await GetCapabilities()).features.schedulingbefore using scheduling to confirm the provider supports it.
Await GetCapabilities() before reading its flags. Use an explicit UTC offset when constructing a Date; the example is 08:45 in Paris on that date. A timezone field does not change how JavaScript parses a timezone-less date string.
Tags and Metadata
Tags and metadata help categorize and track emails for analytics.
| Field | Type | Description |
|---|---|---|
tags | string[] | Labels for categorization and analytics |
metadata | Record<string, string> | Custom key-value pairs returned in webhook events |
import { Send } from "@antelopejs/interface-email";
await Send({
to: "[email protected]",
subject: "Order Confirmation",
html: "<p>Your order #12345 has been confirmed.</p>",
tags: ["transactional", "order-confirmation"],
metadata: {
orderId: "12345",
userId: "usr_abc",
},
});
Provider Options
The providerOptions field passes provider-specific configuration that falls outside the standard interface. Use it sparingly, as it reduces portability.
import { Send } from "@antelopejs/interface-email";
await Send({
to: "[email protected]",
subject: "Test",
text: "Hello",
providerOptions: {
sendgridIpPoolName: "transactional",
},
});
Template Emails
The SendTemplate function renders an email from a template before sending. Templates can be provider-hosted or defined inline.
Provider-hosted templates
Reference a template stored in the provider's system by its ID:
import { SendTemplate } from "@antelopejs/interface-email";
const response = await SendTemplate({
to: "[email protected]",
template: { id: "welcome-v2", version: "3" },
variables: {
name: "Alice",
activationUrl: "https://app.example.com/activate?token=xyz",
},
});
Inline templates
Define the template content directly with an optional engine hint:
import { SendTemplate } from "@antelopejs/interface-email";
const response = await SendTemplate({
to: "[email protected]",
template: {
content: "<h1>Hello {{name}}</h1><p>Welcome to our platform.</p>",
type: "html",
engine: "handlebars",
},
variables: { name: "Alice" },
});
Per-recipient variables
When sending to multiple recipients, provide unique variable values for each one using recipientVariables:
import { SendTemplate } from "@antelopejs/interface-email";
await SendTemplate({
to: ["[email protected]", "[email protected]"],
template: { id: "weekly-digest" },
variables: { week: "March 23-29" },
recipientVariables: {
"[email protected]": { name: "Alice", unreadCount: "5" },
"[email protected]": { name: "Bob", unreadCount: "12" },
},
});
Batch Sending
The SendBatch function sends multiple emails in a single operation. Each message in the batch follows the same EmailParams structure, with an optional batchId for matching responses.
import { SendBatch } from "@antelopejs/interface-email";
const result = await SendBatch({
messages: [
{
to: "[email protected]",
subject: "Your invoice",
html: "<p>Your invoice #001 is ready in your account.</p>",
batchId: "invoice-001",
},
{
to: "[email protected]",
subject: "Your invoice",
html: "<p>Your invoice #002 is ready in your account.</p>",
batchId: "invoice-002",
},
],
defaults: {
from: { email: "[email protected]", name: "Billing" },
tags: ["invoice"],
},
continueOnError: true,
});
Batch defaults
The defaults field applies shared values to all messages. Individual message fields override defaults when both are specified.
Error handling in batches
When continueOnError is true (the default), the batch continues sending even if individual messages fail. The response includes per-message results:
console.log(result.total); // Total messages in batch
console.log(result.successful); // Number sent successfully
console.log(result.failed); // Number that failed
for (const res of result.responses) {
if (!res.success) {
console.error(
`Message ${res.batchId} to ${res.recipient} failed:`,
res.error,
);
}
}
Email Response
The Send and SendTemplate functions return an EmailResponse object:
| Field | Type | Description |
|---|---|---|
success | boolean | Whether the email was accepted |
status | EmailStatus | Current delivery status |
messageId | string | Provider-assigned ID for tracking |
error | EmailError | Error details if the send failed |
timestamp | Date | When the email was accepted |
provider | string | Name of the provider that handled the request |
The EmailStatus type includes these values: "queued", "sent", "delivered", "failed", "rejected", "scheduled", and "unknown".
Only success and status are required on EmailResponse. Message IDs, errors, timestamps, and provider names may be absent. In a batch, each result also has an index into the original messages and a recipient; batchId is optional. The batch-level success is true only when every message succeeds.
Error handling
When success is false, inspect the optional error field for an EmailError object:
import { Send } from "@antelopejs/interface-email";
const response = await Send({
to: "[email protected]",
subject: "Hello",
text: "World",
});
if (!response.success && response.error) {
console.error(`Error [${response.error.code}]: ${response.error.message}`);
if (response.error.retryable) {
// A retry may succeed; apply your retry and duplicate-send policy.
}
}
retryable is a hint, not an idempotency guarantee. Retrying can send another message; the interface does not define a deduplication key. EmailError requires code and message, with optional field and retryable. Also handle rejected promises from the configured implementation.
Next Steps
- Attachments -- Learn how to attach files using buffers, base64, file paths, or URLs.
Introduction
Send transactional messages, templates, and batches through one provider-neutral contract. @antelopejs/interface-email defines the request and response types; an implementing module supplies the email provider and its configuration.
Attachments
The interface supports four attachment types, each suited to a different source of file data. All types share a common BaseAttachment structure and are passed through the attachments field of EmailParams.