How to E2E Test Amazon SES Email Workflows in Playwright

작성자

카테고리:

← 피드로
DEV Community · zerodrop · 2026-06-20 개발(SW)
Cover image for How to E2E Test Amazon SES Email Workflows in Playwright

zerodrop

Amazon SES is the go-to transactional email service for teams already in the AWS ecosystem. But testing SES emails end-to-end in CI is notoriously painful — IAM permissions, sandbox restrictions, and no easy way to catch sent emails programmatically.

This guide shows the complete setup for testing Amazon SES email flows in Playwright using ZeroDrop — no Docker, no shared inboxes, no mocking.

The app we’re testing

A Next.js API route that sends a verification email via Amazon SES:

// app/api/auth/signup/route.ts
import { SESClient, SendEmailCommand } from '@aws-sdk/client-ses';

const ses = new SESClient({
  region: process.env.AWS_REGION!,
  credentials: {
    accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
  },
});

export async function POST(req: Request) {
  const { email } = await req.json();

  const token = crypto.randomUUID();
  const verifyUrl = `${process.env.NEXT_PUBLIC_URL}/verify?token=${token}`;

  await ses.send(new SendEmailCommand({
    Source: '[email protected]',
    Destination: { ToAddresses: [email] },
    Message: {
      Subject: { Data: 'Verify your email' },
      Body: {
        Html: {
          Data: `<p>Click <a href="${verifyUrl}">here</a> to verify your email.</p>`,
        },
      },
    },
  }));

  return Response.json({ success: true });
}

Enter fullscreen mode Exit fullscreen mode

Stage 1 — Local development: SES sandbox mode

When you first create an Amazon SES account, it starts in sandbox mode. In sandbox mode:

  • You can only send emails to verified email addresses
  • You can only send emails from verified email addresses or domains
  • There’s a sending limit of 200 emails per day

This is fine for local development — verify your own email address in the SES console and use it as the test recipient. But sandbox mode completely blocks automated CI testing because you can’t verify a randomly generated @zerodrop-sandbox.online address.

What it solves: Basic local testing with a fixed test email address.

What it doesn’t solve: Automated testing with random addresses, parallel test runs, or CI pipelines.

Stage 2 — Request production access

To use SES with ZeroDrop in CI, you need to move out of sandbox mode. Request production access in the AWS SES console:

  1. Go to SES → Account dashboard
  2. Click Request production access
  3. Fill in your use case — “transactional email for application testing”
  4. AWS typically approves within 24 hours

Once approved, SES can send to any email address including ZeroDrop inboxes.

Stage 3 — CI: SES production + ZeroDrop

npm install zerodrop-client

Enter fullscreen mode Exit fullscreen mode

import { test, expect } from '@playwright/test';
import { ZeroDrop } from 'zerodrop-client';

const mail = new ZeroDrop();

test('user can sign up and verify email', async ({ page }) => {
  // 1. Generate a disposable inbox
  const inbox = process.env.TEST_INBOX ?? mail.generateInbox();
  // → "[email protected]"

  // 2. Sign up — SES sends a real verification email to this inbox
  await page.goto('/signup');
  await page.fill('[data-testid="email"]', inbox);
  await page.click('[data-testid="submit"]');

  await expect(page).toHaveURL('/check-email');

  // 3. ZeroDrop catches the email — magic link auto-extracted
  const email = await mail.waitForLatest(inbox, { timeout: 30000 });

  expect(email.subject).toContain('Verify your email');
  expect(email.magicLink).not.toBeNull();

  // 4. Click the verification link
  await page.goto(email.magicLink!);

  // 5. Assert verified
  await expect(page).toHaveURL('/dashboard');
});

Enter fullscreen mode Exit fullscreen mode

OTP flows

await ses.send(new SendEmailCommand({
  Source: '[email protected]',
  Destination: { ToAddresses: [email] },
  Message: {
    Subject: { Data: 'Your verification code' },
    Body: {
      Html: { Data: `<p>Your code is: <strong>${otp}</strong></p>` },
    },
  },
}));

Enter fullscreen mode Exit fullscreen mode

const email = await mail.waitForLatest(inbox, { timeout: 30000 });

// OTP auto-extracted at the edge — no regex needed
expect(email.otp).not.toBeNull();
await page.fill('[data-testid="otp"]', email.otp!);
await page.click('[data-testid="verify"]');

Enter fullscreen mode Exit fullscreen mode

IAM permissions for CI

Create a dedicated IAM user for CI with minimal permissions:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ses:SendEmail",
        "ses:SendRawEmail"
      ],
      "Resource": "*"
    }
  ]
}

Enter fullscreen mode Exit fullscreen mode

Store AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY as GitHub Actions secrets — never in your codebase.

GitHub Actions workflow

name: E2E Tests

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - run: npm ci

      - run: npx playwright install --with-deps chromium

      - name: Generate test inbox
        id: inbox
        uses: zerodrop-dev/create-inbox@8706a59 # v1.0.0

      - name: Run E2E tests
        run: npx playwright test
        env:
          TEST_INBOX: ${{ steps.inbox.outputs.inbox }}
          AWS_REGION: ${{ secrets.AWS_REGION }}
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          NEXT_PUBLIC_URL: ${{ secrets.STAGING_URL }}

Enter fullscreen mode Exit fullscreen mode

Pro tip: Use GitHub’s OIDC integration with AWS IAM roles instead of long-lived access keys — more secure and no key rotation needed.

The full picture

SES sandbox (local) SES production (staging) SES production + ZeroDrop (CI) Verified recipients only ✅ (limitation) ❌ ❌ Random test addresses ❌ ✅ ✅ Automated in CI ❌ ❌ ✅ Parallel test runs ❌ ❌ ✅ OTP auto-extraction ❌ ❌ ✅ Tests real delivery ❌ ✅ ✅

Request production SES access early — it unlocks automated testing and takes 24 hours to approve. Once approved, the live SES + ZeroDrop combination gives you full E2E coverage in CI.

ZeroDrop — disposable email inboxes for CI pipelines. Free, no signup, no Docker.
zerodrop.dev · docs · npm

원문에서 계속 ↗

코멘트

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다