Configuration
Configure email providers in your application
Last updated:
Configuration
This guide covers how to configure email providers in your application.
Provider Configuration
Each provider has its own configuration options. Here are examples for common providers:
Resend
import { resendProvider } from "@visulima/email/providers/resend";
const resend = resendProvider({
apiKey: process.env.RESEND_API_KEY!,
timeout: 30000, // Optional: request timeout in milliseconds
retries: 3, // Optional: number of retry attempts
});AWS SES
import { awsSesProvider } from "@visulima/email/providers/aws-ses";
const awsSes = awsSesProvider({
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
region: "us-east-1", // Optional, defaults to us-east-1
timeout: 30000, // Optional
retries: 3, // Optional
});SMTP
import { smtpProvider } from "@visulima/email/providers/smtp";
const smtp = smtpProvider({
host: "smtp.example.com",
port: 587,
secure: false, // true for 465, false for other ports
user: process.env.SMTP_USER!,
password: process.env.SMTP_PASSWORD!,
timeout: 30000, // Optional
retries: 3, // Optional
});Zeptomail
import { zeptomailProvider } from "@visulima/email/providers/zeptomail";
const zeptomail = zeptomailProvider({
token: process.env.ZEPTOMAIL_TOKEN!, // Format: "Zoho-enczapikey <your_api_key>"
timeout: 30000, // Optional
retries: 3, // Optional
});Brevo
import { brevoProvider } from "@visulima/email/providers/brevo";
const brevo = brevoProvider({
apiKey: process.env.BREVO_API_KEY!,
endpoint: "https://api.brevo.com/v3", // Optional, defaults to this
timeout: 30000, // Optional
retries: 3, // Optional
});Mailjet
import { mailjetProvider } from "@visulima/email/providers/mailjet";
const mailjet = mailjetProvider({
apiKey: process.env.MAILJET_API_KEY!,
apiSecret: process.env.MAILJET_API_SECRET!,
endpoint: "https://api.mailjet.com", // Optional, defaults to this
timeout: 30000, // Optional
retries: 3, // Optional
});MailerSend
import { mailerSendProvider } from "@visulima/email/providers/mailersend";
const mailerSend = mailerSendProvider({
apiToken: process.env.MAILERSEND_API_TOKEN!,
endpoint: "https://api.mailersend.com", // Optional, defaults to this
timeout: 30000, // Optional
retries: 3, // Optional
});Mandrill
import { mandrillProvider } from "@visulima/email/providers/mandrill";
const mandrill = mandrillProvider({
apiKey: process.env.MANDRILL_API_KEY!,
endpoint: "https://mandrillapp.com/api/1.0", // Optional, defaults to this
timeout: 30000, // Optional
retries: 3, // Optional
});MailPace
import { mailPaceProvider } from "@visulima/email/providers/mailpace";
const mailPace = mailPaceProvider({
apiToken: process.env.MAILPACE_API_TOKEN!,
endpoint: "https://app.mailpace.com/api/v1", // Optional, defaults to this
timeout: 30000, // Optional
retries: 3, // Optional
});Mailtrap
import { mailtrapProvider } from "@visulima/email/providers/mailtrap";
const mailtrap = mailtrapProvider({
apiToken: process.env.MAILTRAP_API_TOKEN!,
endpoint: "https://send.api.mailtrap.io", // Optional, defaults to this
timeout: 30000, // Optional
retries: 3, // Optional
});Postal
import { postalProvider } from "@visulima/email/providers/postal";
const postal = postalProvider({
host: process.env.POSTAL_HOST!,
apiKey: process.env.POSTAL_API_KEY!,
endpoint: `https://${process.env.POSTAL_HOST}/api/v1`, // Optional, auto-generated from host
timeout: 30000, // Optional
retries: 3, // Optional
});Azure Communication Services
import { azureProvider } from "@visulima/email/providers/azure";
// Using access token
const azure = azureProvider({
accessToken: process.env.AZURE_ACCESS_TOKEN!,
region: process.env.AZURE_REGION!, // e.g., "eastus", "westus"
endpoint: `https://${process.env.AZURE_REGION}.communication.azure.com`, // Optional, auto-generated
timeout: 30000, // Optional
retries: 3, // Optional
});
// Or using connection string
const azureWithConnectionString = azureProvider({
connectionString: process.env.AZURE_CONNECTION_STRING!,
region: process.env.AZURE_REGION!,
});Infobip
import { infobipProvider } from "@visulima/email/providers/infobip";
const infobip = infobipProvider({
apiKey: process.env.INFOBIP_API_KEY!,
baseUrl: "https://api.infobip.com", // Optional, defaults to this
timeout: 30000, // Optional
retries: 3, // Optional
});Scaleway
import { scalewayProvider } from "@visulima/email/providers/scaleway";
const scaleway = scalewayProvider({
apiKey: process.env.SCALEWAY_API_KEY!,
region: process.env.SCALEWAY_REGION!, // e.g., "fr-par", "nl-ams"
endpoint: "https://api.scaleway.com/transactional-email/v1alpha1", // Optional, defaults to this
timeout: 30000, // Optional
retries: 3, // Optional
});AhaSend
import { ahaSendProvider } from "@visulima/email/providers/ahasend";
const ahaSend = ahaSendProvider({
apiKey: process.env.AHASEND_API_KEY!,
endpoint: "https://api.ahasend.com", // Optional, defaults to this
timeout: 30000, // Optional
retries: 3, // Optional
});Mailomat
import { mailomatProvider } from "@visulima/email/providers/mailomat";
const mailomat = mailomatProvider({
apiKey: process.env.MAILOMAT_API_KEY!,
endpoint: "https://api.mailomat.com", // Optional, defaults to this
timeout: 30000, // Optional
retries: 3, // Optional
});Sweego
import { sweegoProvider } from "@visulima/email/providers/sweego";
const sweego = sweegoProvider({
apiKey: process.env.SWEEGO_API_KEY!,
endpoint: "https://api.sweego.com", // Optional, defaults to this
timeout: 30000, // Optional
retries: 3, // Optional
});Mailgun
import { mailgunProvider } from "@visulima/email/providers/mailgun";
const mailgun = mailgunProvider({
apiKey: process.env.MAILGUN_API_KEY!,
domain: process.env.MAILGUN_DOMAIN!, // Required: Your Mailgun domain
endpoint: "https://api.mailgun.net", // Optional: Use https://api.eu.mailgun.net for EU accounts
timeout: 30000, // Optional
retries: 3, // Optional
});Postmark
import { postmarkProvider } from "@visulima/email/providers/postmark";
const postmark = postmarkProvider({
serverToken: process.env.POSTMARK_SERVER_TOKEN!,
endpoint: "https://api.postmarkapp.com", // Optional, defaults to this
timeout: 30000, // Optional
retries: 3, // Optional
});SendGrid
import { sendGridProvider } from "@visulima/email/providers/sendgrid";
const sendgrid = sendGridProvider({
apiKey: process.env.SENDGRID_API_KEY!,
endpoint: "https://api.sendgrid.com/v3", // Optional, defaults to this
timeout: 30000, // Optional
retries: 3, // Optional
});Plunk
import { plunkProvider } from "@visulima/email/providers/plunk";
const plunk = plunkProvider({
apiKey: process.env.PLUNK_API_KEY!,
endpoint: "https://api.useplunk.com/v1", // Optional, defaults to this
timeout: 30000, // Optional
retries: 3, // Optional
});Mock (for Testing)
import { mockProvider } from "@visulima/email/providers/mock";
const mock = mockProvider({
debug: true, // Optional: enable debug logging
delay: 100, // Optional: simulate delay in milliseconds
failureRate: 0.1, // Optional: failure rate (0.0 to 1.0)
simulateFailure: false, // Optional: always fail if true
timeout: 0, // Optional: not used by mock provider
retries: 0, // Optional: not used by mock provider
});Mail Options
createMail accepts an optional second argument to configure the Mail instance itself (as opposed to the provider):
import { createMail } from "@visulima/email";
import { resendProvider } from "@visulima/email/providers/resend";
const mail = createMail(resendProvider({ apiKey: "re_xxx" }), {
featureCheck: "error", // "error" (default) | "warn" | "off"
});featureCheck controls the fail-fast capability guard, which rejects messages that use fields the provider has explicitly declared unsupported before they reach the network. See the dedicated guide for details.
Environment Variables
It's recommended to store sensitive configuration in environment variables:
# .env
RESEND_API_KEY=re_xxx
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
SMTP_USER=user@example.com
SMTP_PASSWORD=password
ZEPTOMAIL_TOKEN=Zoho-enczapikey YOUR_API_KEY_HERE
BREVO_API_KEY=your-brevo-api-key
MAILJET_API_KEY=your-mailjet-api-key
MAILJET_API_SECRET=your-mailjet-api-secret
MAILERSEND_API_TOKEN=your-mailersend-api-token
MANDRILL_API_KEY=your-mandrill-api-key
MAILPACE_API_TOKEN=your-mailpace-api-token
MAILTRAP_API_TOKEN=your-mailtrap-api-token
POSTAL_HOST=your-postal-server.com
POSTAL_API_KEY=your-postal-api-key
AZURE_ACCESS_TOKEN=your-azure-access-token
AZURE_REGION=eastus
AZURE_CONNECTION_STRING=endpoint=https://...;accesskey=...
INFOBIP_API_KEY=your-infobip-api-key
SCALEWAY_API_KEY=your-scaleway-api-key
SCALEWAY_REGION=fr-par
AHASEND_API_KEY=your-ahasend-api-key
MAILOMAT_API_KEY=your-mailomat-api-key
SWEEGO_API_KEY=your-sweego-api-key
MAILGUN_API_KEY=your-mailgun-api-key
MAILGUN_DOMAIN=your-domain.com
POSTMARK_SERVER_TOKEN=your-postmark-server-token
SENDGRID_API_KEY=SG.your-sendgrid-api-key
PLUNK_API_KEY=your-plunk-api-keyThen use them in your code:
const resend = resendProvider({
apiKey: process.env.RESEND_API_KEY!,
});Typing Configuration
If you want to type your configuration objects, you can import the config types from each provider:
import { resendProvider, type ResendConfig } from "@visulima/email/providers/resend";
import { smtpProvider, type SmtpConfig } from "@visulima/email/providers/smtp";
// Type your configuration
const resendConfig: ResendConfig = {
apiKey: process.env.RESEND_API_KEY!,
timeout: 30000,
retries: 3,
};
const smtpConfig: SmtpConfig = {
host: "smtp.example.com",
port: 587,
secure: false,
user: process.env.SMTP_USER!,
password: process.env.SMTP_PASSWORD!,
};
// Use typed configs
const resend = resendProvider(resendConfig);
const smtp = smtpProvider(smtpConfig);Each provider exports its own config type from its provider path. For example:
ResendConfigfrom@visulima/email/providers/resendSmtpConfigfrom@visulima/email/providers/smtpAwsSesConfigfrom@visulima/email/providers/aws-sesBrevoConfigfrom@visulima/email/providers/brevoMailgunConfigfrom@visulima/email/providers/mailgunMailjetConfigfrom@visulima/email/providers/mailjetMailerSendConfigfrom@visulima/email/providers/mailersendMandrillConfigfrom@visulima/email/providers/mandrillMailPaceConfigfrom@visulima/email/providers/mailpaceMailtrapConfigfrom@visulima/email/providers/mailtrapPostalConfigfrom@visulima/email/providers/postalPostmarkConfigfrom@visulima/email/providers/postmarkAzureConfigfrom@visulima/email/providers/azureInfobipConfigfrom@visulima/email/providers/infobipScalewayConfigfrom@visulima/email/providers/scalewayAhaSendConfigfrom@visulima/email/providers/ahasendMailomatConfigfrom@visulima/email/providers/mailomatSweegoConfigfrom@visulima/email/providers/sweegoSendGridConfigfrom@visulima/email/providers/sendgridPlunkConfigfrom@visulima/email/providers/plunkMockConfigfrom@visulima/email/providers/mockOpenTelemetryConfigfrom@visulima/email/providers/opentelemetry- And so on for other providers
Provider Factory Pattern
All providers follow a factory pattern. They return a ProviderFactory function that creates a provider instance:
import { resendProvider } from "@visulima/email/providers/resend";
// resendProvider is a factory function
const providerFactory = resendProvider;
// Call it with configuration to get a provider
const provider = providerFactory({ apiKey: "re_xxx" });Multiple Providers
You can configure multiple providers and switch between them:
import { createMail } from "@visulima/email";
import { resendProvider } from "@visulima/email/providers/resend";
import { smtpProvider } from "@visulima/email/providers/smtp";
const resend = resendProvider({ apiKey: "re_xxx" });
const smtp = smtpProvider({
host: "smtp.example.com",
port: 587,
user: "user@example.com",
password: "password",
});
// Use Resend for production
const productionMail = createMail(resend);
// Use SMTP for development
const developmentMail = createMail(smtp);Failover Configuration
Configure failover to automatically switch providers on failure:
import { failoverProvider } from "@visulima/email/providers/failover";
import { resendProvider } from "@visulima/email/providers/resend";
import { smtpProvider } from "@visulima/email/providers/smtp";
const failover = failoverProvider({
mailers: [
resendProvider({ apiKey: "re_xxx" }),
smtpProvider({
host: "smtp.example.com",
port: 587,
user: "user@example.com",
password: "password",
}),
],
retryAfter: 60, // Wait 60 seconds before trying next provider
timeout: 30000,
retries: 3,
});Round Robin Configuration
Configure round robin for load balancing:
import { roundRobinProvider } from "@visulima/email/providers/roundrobin";
import { resendProvider } from "@visulima/email/providers/resend";
import { smtpProvider } from "@visulima/email/providers/smtp";
const roundRobin = roundRobinProvider({
mailers: [
resendProvider({ apiKey: "re_xxx" }),
smtpProvider({
host: "smtp.example.com",
port: 587,
user: "user@example.com",
password: "password",
}),
],
retryAfter: 60,
timeout: 30000,
retries: 3,
});Default Email Configuration
You can configure default values for all emails sent through a Mail instance. This is useful when you want to set a default from address, replyTo address, or headers that apply to all emails.
Setting Default From Address
import { createMail } from "@visulima/email";
import { resendProvider } from "@visulima/email/providers/resend";
const mail = createMail(resendProvider({ apiKey: "re_xxx" }));
// Set default from address
mail.setFrom({ email: "noreply@example.com", name: "My App" });
// Now all emails will use this from address if not specified
const message = new MailMessage().to("user@example.com").subject("Hello").html("<h1>Hello World</h1>");
// No need to set .from() - it will use the default
await mail.send(message);Setting Default Reply-To Address
const mail = createMail(resendProvider({ apiKey: "re_xxx" }));
// Set default reply-to address
mail.setReplyTo({ email: "support@example.com" });
// All emails will include this reply-to if not specified in the messageSetting Default Headers
const mail = createMail(resendProvider({ apiKey: "re_xxx" }));
// Set default headers
mail.setHeaders({
"X-App-Name": "MyApp",
"X-Version": "1.0.0",
"X-Environment": "production",
});
// These headers will be added to all emails
// Message-specific headers will take precedence if they conflictChaining Configuration Methods
You can chain the configuration methods together:
const mail = createMail(resendProvider({ apiKey: "re_xxx" }))
.setFrom({ email: "noreply@example.com", name: "My App" })
.setReplyTo({ email: "support@example.com" })
.setHeaders({ "X-App-Name": "MyApp" });Overriding Defaults
Default values are only applied if the corresponding field is not set in the message:
const mail = createMail(resendProvider({ apiKey: "re_xxx" }));
mail.setFrom({ email: "noreply@example.com" });
// This message will use the default from address
const message1 = new MailMessage().to("user@example.com").subject("Hello").html("<h1>Hello</h1>");
await mail.send(message1); // Uses noreply@example.com
// This message overrides the default
const message2 = new MailMessage()
.to("user@example.com")
.from({ email: "custom@example.com" }) // Overrides default
.subject("Hello")
.html("<h1>Hello</h1>");
await mail.send(message2); // Uses custom@example.comHeader Merging
When setting default headers, they are merged with message-specific headers. Message headers take precedence:
const mail = createMail(resendProvider({ apiKey: "re_xxx" }));
mail.setHeaders({
"X-App-Name": "MyApp",
"X-Version": "1.0.0",
});
const message = new MailMessage()
.to("user@example.com")
.from("sender@example.com")
.subject("Hello")
.html("<h1>Hello</h1>")
.header("X-Version", "2.0.0") // Overrides default
.header("X-Custom", "value"); // Additional header
// Final headers will be:
// X-App-Name: MyApp (from default)
// X-Version: 2.0.0 (from message, overrides default)
// X-Custom: value (from message)Next Steps
- Sending Mail - Learn how to send emails
- Providers - Explore all available providers