Toast
ContributorDrivers

Email Driver Testing Guide

Email Driver Testing Guide

Manual test plan for verifying email driver functionality.

What's Been Implemented

IssueFeatureStatus
#346Driver interface + Mailgun driverComplete
#347Resend driverNot started
#348Batch sendingNot started
#349Webhook handlingNot started
#350DocumentationNot started

1. Testing the Console Driver (Development)

The console driver is used automatically in development when EMAIL_DRIVER is not set.

Quick Test

# 1. Start the dev environment
pnpm dx

# 2. Open admin panel
open http://localhost:5173

# 3. Click "Sign in with email link"
# 4. Enter: admin@ghost.org
# 5. Click submit

Expected Output in API Terminal

============================================================
EMAIL SENT (console driver)
============================================================
Message ID: console-1738594000000-1
To:         admin@ghost.org
From:       undefined
Subject:    Sign in to Toast
------------------------------------------------------------
HTML: <p>Click the link below to sign in:</p><p><a href="http://localhost:5173/api/auth/magic-link/verify?token=...">...</a></p>
------------------------------------------------------------
Text: Sign in to Toast

Click the link below to sign in to your account...
============================================================

Note: From: undefined appears when the EMAIL_FROM environment variable is not set. In development this is fine, but for production you should set EMAIL_FROM=noreply@yourdomain.com in your .env file.

Copy the URL from the output and paste it in your browser to complete login.

2. Testing the Mailgun Driver

The Mailgun driver is included in the monorepo as a workspace package (drivers/email-mailgun/).

Setup

# Configure environment variables in .env:
EMAIL_DRIVER=toast-driver-email-mailgun
MAILGUN_API_KEY=key-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
MAILGUN_DOMAIN=mg.yourdomain.com
MAILGUN_REGION=us  # or 'eu' for EU region

# Restart the API
pnpm dev

Test

  1. Request a magic link from the admin panel
  2. Check your actual email inbox - the email should arrive
  3. Verify in Mailgun dashboard: https://app.mailgun.com/mg/dashboard

Verify Logs

Look for successful send in API logs:

{
  "level": "info",
  "email": "...",
  "messageId": "<abc123@mg.domain.com>",
  "driver": "mailgun",
  "event": "magic_link.sent"
}

3. Switching Between Drivers

Verify the driver abstraction works by switching drivers:

# Test 1: Console driver (development default)
# In .env: EMAIL_DRIVER=console (or leave unset)
pnpm dev
# Result: Emails logged to console

# Test 2: Switch to Mailgun
# In .env: EMAIL_DRIVER=toast-driver-email-mailgun + credentials
pnpm dev
# Result: Emails sent via Mailgun

Both should successfully send the magic link email with the same user flow.

4. Running Unit Tests

# Run all email driver tests
pnpm test packages/drivers/src/email/
pnpm test drivers/email-mailgun/

# Or run with coverage
pnpm test:coverage --filter=@toast/drivers
pnpm test:coverage --filter=toast-driver-email-mailgun

All drivers should have 100% coverage.

5. Testing Email in Your Own Code

Using ConsoleEmailDriver for Assertions

import { ConsoleEmailDriver, getEmailDriver, resetEmailDriver } from '@toast/drivers';

beforeEach(() => {
  resetEmailDriver(); // Clear cached driver
});

it('sends welcome email', async () => {
  const driver = await getEmailDriver();

  // ... your code that sends email ...

  // Assert on captured emails
  const sent = (driver as ConsoleEmailDriver).getSentEmails();
  expect(sent).toHaveLength(1);
  expect(sent[0]?.message.to).toBe('user@example.com');
  expect(sent[0]?.message.subject).toContain('Welcome');
});

Mocking the Driver in Unit Tests

// Set up mock before imports
const mockEmailDriver = vi.hoisted(() => ({
  name: 'mock',
  send: vi.fn().mockResolvedValue({ success: true, messageId: 'mock-123' }),
}));

vi.mock('@toast/drivers', () => ({
  getEmailDriver: vi.fn().mockResolvedValue(mockEmailDriver),
}));

// Test success
it('sends email successfully', async () => {
  await yourFunctionThatSendsEmail();

  expect(mockEmailDriver.send).toHaveBeenCalledWith(
    expect.objectContaining({
      to: 'expected@example.com',
      subject: expect.stringContaining('Expected Subject'),
    })
  );
});

// Test failure handling
it('handles email failure gracefully', async () => {
  mockEmailDriver.send.mockResolvedValueOnce({
    success: false,
    error: 'SMTP connection failed',
  });

  await expect(yourFunctionThatSendsEmail()).rejects.toThrow();
});

6. Production Readiness Checklist

Before deploying to production:

  • Set EMAIL_DRIVER explicitly (required in production)
  • Configure provider credentials (MAILGUN_*)
  • Verify sending domain is authenticated with provider
  • Test magic link flow end-to-end
  • Check logs show magic_link.sent events
  • Verify emails land in inbox (not spam)

Quick Reference

DriverEnvironment Variables
ConsoleNone (or EMAIL_DRIVER=console)
MailgunEMAIL_DRIVER=toast-driver-email-mailgunMAILGUN_API_KEYMAILGUN_DOMAINMAILGUN_REGION (optional, default: us)EMAIL_FROM (optional)

On this page