Email Driver Testing Guide
Email Driver Testing Guide
Manual test plan for verifying email driver functionality.
What's Been Implemented
| Issue | Feature | Status |
|---|---|---|
| #346 | Driver interface + Mailgun driver | Complete |
| #347 | Resend driver | Not started |
| #348 | Batch sending | Not started |
| #349 | Webhook handling | Not started |
| #350 | Documentation | Not 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 submitExpected 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: undefinedappears when theEMAIL_FROMenvironment variable is not set. In development this is fine, but for production you should setEMAIL_FROM=noreply@yourdomain.comin your.envfile.
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 devTest
- Request a magic link from the admin panel
- Check your actual email inbox - the email should arrive
- 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 MailgunBoth 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-mailgunAll 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_DRIVERexplicitly (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.sentevents - Verify emails land in inbox (not spam)
Quick Reference
| Driver | Environment Variables |
|---|---|
| Console | None (or EMAIL_DRIVER=console) |
| Mailgun | EMAIL_DRIVER=toast-driver-email-mailgunMAILGUN_API_KEYMAILGUN_DOMAINMAILGUN_REGION (optional, default: us)EMAIL_FROM (optional) |