Search docs

Jump between documentation pages.

Email integrations

DaloyJS doesn't ship its own email transport. Send mail by registering a small plugin that decorates app.state with a provider client, then call it from your route handlers. The pages in this section show how to wire up the six most common transactional email providers using their official Node SDKs.

Supported providers

  • AWS SES (SESv2) — pay-as-you-go SMTP/HTTP at AWS scale via @aws-sdk/client-sesv2. Best fit when you already run on AWS or need the cheapest per-message price.
  • SendGrid — Twilio's established sender via @sendgrid/mail. Good for high-volume marketing plus transactional.
  • Resend — modern, developer-first API via the resend SDK. Great DX, React Email templating, edge-friendly.
  • Postmark — transactional-first delivery via the postmark SDK. Known for very high inbox placement.
  • Mailgun — Sinch-backed sender via mailgun.js. Strong validation, routing, and EU/US regions.
  • Mailtrap — sandbox + production sending via the mailtrap SDK. Switch between a test inbox and live sending with a single flag.

Runtime compatibility at a glance

Most provider SDKs are HTTPS-based and work on every runtime DaloyJS targets, but a few depend on Node-only APIs (filesystem, TCP, AWS Signature V4 with NodeHttpHandler) and won't run on Cloudflare Workers or Vercel Edge without adjustments.

ProviderNode / Bun / DenoCloudflare WorkersVercel EdgeAWS Lambda
AWS SES (SESv2)YesWith fetch handler & static credsWith fetch handler & static credsYes (IAM role)
SendGridYesUse Web API via fetch (SDK is Node-oriented)Use Web API via fetchYes
ResendYesYesYesYes
PostmarkYesCall REST via fetch (SDK uses axios)Call REST via fetchYes
MailgunYesYes (enable useFetch: true in v12.1+)Yes (useFetch: true)Yes
MailtrapYesCall REST via fetch (SDK uses Node features)Call REST via fetchYes

Common pattern

Every guide in this section follows the same three steps: install the SDK, register a DaloyJS plugin that puts the client on app.state, then call it inside a validated route handler. The plugin shape is intentionally tiny so you can swap providers without touching business logic:

// src/plugins/email.ts
import type { App } from "@daloyjs/core";

export interface EmailMessage {
  to: string;
  subject: string;
  text?: string;
  html?: string;
}

export interface EmailSender {
  send(msg: EmailMessage): Promise<{ id: string }>;
}

export function emailPlugin(sender: EmailSender) {
  return {
    name: "email",
    register(app: App) {
      app.decorate("email", sender);
    },
  };
}

declare module "@daloyjs/core" {
  interface AppState {
    email: EmailSender;
  }
}

Each provider page implements EmailSender with the official SDK so the rest of your app stays provider-agnostic.

Security checklist

  • Keep API keys in environment variables. Never commit them. Use AWS IAM roles on Lambda and platform-managed secrets on Vercel, Cloudflare, Fly, and Render.
  • Verify your sending domain. Add SPF, DKIM, and DMARC records before going live; every provider here rejects unverified senders in production.
  • Validate inputs. Treat the to, subject, and body as untrusted. Use DaloyJS validation with z.string().email() to block header injection.
  • Rate-limit the send route. Use the built-in rateLimit middleware (or the Redis store) on any endpoint that triggers email so abuse can't drive your bill or reputation down.
  • Verify provider webhooks. If you process bounces, complaints, or opens, verify the signature on every incoming webhook before trusting its payload.