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
});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