Providers Introduction

Learn about email providers in @visulima/email

Last updated:

Providers

Providers are responsible for actually sending emails. @visulima/email supports multiple providers, allowing you to choose the best one for your needs or switch providers without changing your code.

Available Providers

Runtime Support

Different providers support different JavaScript runtimes. Choose providers based on your deployment target:

Universal Providers (All Runtimes)

These providers work in Node.js, Deno, Bun, and Cloudflare Workers:

  • Resend - Uses Fetch API, works everywhere
  • HTTP - Uses Fetch API, works everywhere
  • Zeptomail - Uses Fetch API, works everywhere
  • Brevo - Uses Fetch API, works everywhere
  • Mailgun - Uses Fetch API, works everywhere
  • Mailjet - Uses Fetch API, works everywhere
  • MailerSend - Uses Fetch API, works everywhere
  • Mandrill - Uses Fetch API, works everywhere
  • MailPace - Uses Fetch API, works everywhere
  • Mailtrap - Uses Fetch API, works everywhere
  • Postal - Uses Fetch API, works everywhere
  • Postmark - Uses Fetch API, works everywhere
  • Azure - Uses Fetch API, works everywhere (requires OAuth2 token or connection string)
  • Infobip - Uses Fetch API, works everywhere
  • Scaleway - Uses Fetch API, works everywhere
  • AhaSend - Uses Fetch API, works everywhere
  • Mailomat - Uses Fetch API, works everywhere
  • Sweego - Uses Fetch API, works everywhere
  • SendGrid - Uses Fetch API, works everywhere
  • Plunk - Uses Fetch API, works everywhere
  • Mock - In-memory provider, works everywhere
  • Failover - Works if all wrapped providers support your runtime
  • Round Robin - Works if all wrapped providers support your runtime
  • OpenTelemetry - Works if wrapped provider supports your runtime

Node.js Only Providers

These providers require Node.js built-in modules and only work in Node.js:

  • ⚠️ AWS SES - Requires node:crypto for AWS Signature V4 signing
  • ⚠️ SMTP - Requires node:net and node:tls for SMTP connections
  • ⚠️ MailCrab - Wraps SMTP provider (requires Node.js)
  • ⚠️ Nodemailer - Requires the nodemailer package (Node.js only)

Runtime Compatibility

ProviderNode.jsDenoBunCloudflare Workers
Resend
HTTP
Zeptomail
Brevo
Mailgun
Mailjet
MailerSend
Mandrill
MailPace
Mailtrap
Postal
Postmark
Azure
Infobip
Scaleway
AhaSend
Mailomat
Sweego
SendGrid
Plunk
Mock
AWS SES
SMTP
MailCrab
Nodemailer
Failover✅*✅*✅*✅*
Round Robin✅*✅*✅*✅*
OpenTelemetry✅*✅*✅*✅*

* Runtime support depends on the wrapped providers. Works if all wrapped providers support the runtime.

Choosing a Provider

  • For Cloudflare Workers, Deno, or Bun: Use Resend, HTTP, Zeptomail, Brevo, Mailgun, Mailjet, MailerSend, Mandrill, MailPace, Mailtrap, Postal, Postmark, SendGrid, Plunk, Azure, Infobip, Scaleway, AhaSend, Mailomat, Sweego, or Mock
  • For Node.js: You can use any provider
  • For testing: Use Mock or Mailtrap provider to test email logic without sending real emails
  • For observability: Use OpenTelemetry provider to wrap any provider and add distributed tracing and metrics
  • For cross-runtime compatibility: Use Resend, HTTP, Zeptomail, Brevo, Mailgun, Mailjet, MailerSend, Mandrill, MailPace, Mailtrap, Postal, Postmark, SendGrid, Plunk, Azure, Infobip, Scaleway, AhaSend, Mailomat, Sweego, or Mock, or wrap Node.js-only providers in Failover/Round Robin with universal providers as fallbacks

Provider Interface

All providers implement a common interface:

interface Provider {
    initialize(opts?: Record<string, unknown>): Promise<void>;
    isAvailable(): Promise<boolean>;
    sendEmail(options: EmailOptions): Promise<Result<EmailResult>>;
    validateCredentials?(): Promise<boolean>;
    getEmail?(id: string): Promise<Result<unknown>>;
    shutdown?(): Promise<void>;
}

Using Providers

Import from Separate Exports

Each provider is exported from its own path for better tree-shaking:

import { resendProvider } from "@visulima/email/providers/resend";
import { smtpProvider } from "@visulima/email/providers/smtp";

Create Provider Instance

const resend = resendProvider({
    apiKey: "re_xxx",
});

Use with Mail

import { createMail } from "@visulima/email";

const mail = createMail(resend);

Switching Providers

Since all providers implement the same interface, you can switch providers without changing your email code:

import { createMail, MailMessage } from "@visulima/email";

// Use Resend in production
const productionMail = createMail(resendProvider({ apiKey: process.env.RESEND_API_KEY! }));

// Use SMTP in development
const developmentMail = createMail(
    smtpProvider({
        host: "localhost",
        port: 1025,
        secure: false,
    }),
);

// Same code works with both
const sendEmail = async (mail: Mail) => {
    const message = new MailMessage().to("user@example.com").from("sender@example.com").subject("Hello").html("<h1>Hello</h1>");
    await mail.send(message);
};

Provider-Specific Options

Some providers support additional options in EmailOptions:

Resend

import type { ResendEmailOptions } from "@visulima/email/providers/resend";

const options: ResendEmailOptions = {
    from: { email: "sender@example.com" },
    to: "user@example.com",
    subject: "Hello",
    html: "<h1>Hello</h1>",
    tags: [{ name: "category", value: "welcome" }], // Resend-specific
};

Next Steps

  • Explore individual provider documentation
  • Configuration - Learn how to configure providers
Support

Contribute to our work and keep us going

Community is the heart of open source. The success of our packages wouldn't be possible without the incredible contributions of users, testers, and developers who collaborate with us every day.Want to get involved? Here are some tips on how you can make a meaningful impact on our open source projects.

Ready to help us out?

Be sure to check out the package's contribution guidelines first. They'll walk you through the process on how to properly submit an issue or pull request to our repositories.

Submit a pull request

Found something to improve? Fork the repo, make your changes, and open a PR. We review every contribution and provide feedback to help you get merged.

Good first issues

Simple issues suited for people new to open source development, and often a good place to start working on a package.
View good first issues