Skip to content

SMTP module: Add E2E testing API (search, wait, extract, stats)#334

Merged
butschster merged 3 commits into
masterfrom
copilot/add-smtp-testing-endpoints
May 12, 2026
Merged

SMTP module: Add E2E testing API (search, wait, extract, stats)#334
butschster merged 3 commits into
masterfrom
copilot/add-smtp-testing-endpoints

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 12, 2026

Buggregator's fake SMTP server captures emails but lacked the API surface needed for E2E test suites (Playwright, Cypress, PHPUnit, etc.) to find messages, wait for arrival, and extract links/codes without hand-rolling polling loops and HTML regex parsers.

New endpoints (/api/smtp/)

Endpoint Purpose
GET /api/smtp/cursor Returns server time as an RFC3339 token — grab before triggering an action, pass as since to avoid stale matches
GET /api/smtp/messages Search with filters: to, from, cc, subject, subject_contains, subject_regex, body_contains, since, until, project, limit, offset, order
GET /api/smtp/messages/wait Long-poll — holds until a matching message arrives or timeout expires (default 30s, max 60s); returns 408 on timeout; accepts the same filters as search
GET /api/smtp/message/{uuid}/raw Original RFC 822 source (message/rfc822)
GET /api/smtp/message/{uuid}/links All unique hyperlinks from HTML (with anchor text) and plain-text parts
GET /api/smtp/message/{uuid}/codes Regex code extractor (default \b\d{4,8}\b); custom pattern param; 400 on invalid regex
DELETE /api/smtp/messages Purge mailbox, optionally scoped to ?project=
GET /api/smtp/stats {count, last_received_at} — smoke-check that SMTP transport is wired

Typical E2E flow

// 1. Grab cursor before triggering the signup
const { cursor } = await fetch('/api/smtp/cursor').then(r => r.json())

// 2. Trigger action (sign up, password reset, 2FA, …)
await page.click('#signup')

// 3. Wait for the email (long-poll, no polling loop needed)
const msg = await fetch(
  `/api/smtp/messages/wait?to=alice@example.com&subject_contains=verify&since=${cursor}&timeout=30s`
).then(r => r.json())

// 4. Extract the magic link
const { data: links } = await fetch(`/api/smtp/message/${msg.uuid}/links`).then(r => r.json())
await page.goto(links[0].url)

Module changes

  • module.goRegisterRoutes override wires all endpoints; OnEventStored + subscribe() implement the long-poll waiter (subscribe-before-check pattern eliminates the race between "no existing match" and "event just arrived").
  • handler.goAuthPlain now extracts project from the SMTP AUTH username (test-run-42@smtp → project test-run-42), enabling per-mailbox isolation for parallel CI workers. Reset() clears the extracted project.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • go.yaml.in
    • Triggering command: /dependabot-proxy /dependabot-proxy RETURN mpile 0.1-go1.26.1.linux-amd64/pkg/tool/linux_amd64/vet 2737�� 9e8a34caf7439976049817a4181f4a2d397/config.json ler.go -main/dist/gh-gpgsign/gh-gpgsign-linux-x86_64 --gdwarf-5 ce t -main/dist/gh-gp--no-checkout (dns block)
    • Triggering command: /dependabot-proxy /dependabot-proxy ang/prometheus/prev-parse t ux-amd64/pkg/tool/linux_amd64/compile -W .test t rg/toolchain@v0.0.1-go1.26.1.linux-amd64/pkg/tool/linux_amd64/vet . egator/go-buggre--wait t rg/toolchain@v0.filter -I /smtp/module.go om/prometheus/cl! rg/toolchain@v0.-i --gdwarf-5 s140/hkdf/cast.g/etc/ca-certificates/update.d/ l/linux_amd64/cobr-8684506c92c8 rg/toolchain@v0.-j (dns block)
  • google.golang.org
    • Triggering command: /dependabot-proxy /dependabot-proxy RETURN mpile 0.1-go1.26.1.linux-amd64/pkg/tool/linux_amd64/vet 2737�� 9e8a34caf7439976049817a4181f4a2d397/config.json ler.go -main/dist/gh-gpgsign/gh-gpgsign-linux-x86_64 --gdwarf-5 ce t -main/dist/gh-gp--no-checkout (dns block)
    • Triggering command: /dependabot-proxy /dependabot-proxy ang/prometheus/prev-parse t ux-amd64/pkg/tool/linux_amd64/compile -W .test t rg/toolchain@v0.0.1-go1.26.1.linux-amd64/pkg/tool/linux_amd64/vet . egator/go-buggre--wait t rg/toolchain@v0.filter -I /smtp/module.go om/prometheus/cl! rg/toolchain@v0.-i --gdwarf-5 s140/hkdf/cast.g/etc/ca-certificates/update.d/ l/linux_amd64/cobr-8684506c92c8 rg/toolchain@v0.-j (dns block)
  • gopkg.in
    • Triggering command: /dependabot-proxy /dependabot-proxy RETURN mpile 0.1-go1.26.1.linux-amd64/pkg/tool/linux_amd64/vet 2737�� 9e8a34caf7439976049817a4181f4a2d397/config.json ler.go -main/dist/gh-gpgsign/gh-gpgsign-linux-x86_64 --gdwarf-5 ce t -main/dist/gh-gp--no-checkout (dns block)
    • Triggering command: /dependabot-proxy /dependabot-proxy ang/prometheus/prev-parse t ux-amd64/pkg/tool/linux_amd64/compile -W .test t rg/toolchain@v0.0.1-go1.26.1.linux-amd64/pkg/tool/linux_amd64/vet . egator/go-buggre--wait t rg/toolchain@v0.filter -I /smtp/module.go om/prometheus/cl! rg/toolchain@v0.-i --gdwarf-5 s140/hkdf/cast.g/etc/ca-certificates/update.d/ l/linux_amd64/cobr-8684506c92c8 rg/toolchain@v0.-j (dns block)
  • modernc.org
    • Triggering command: /dependabot-proxy /dependabot-proxy RETURN mpile 0.1-go1.26.1.linux-amd64/pkg/tool/linux_amd64/vet 2737�� 9e8a34caf7439976049817a4181f4a2d397/config.json ler.go -main/dist/gh-gpgsign/gh-gpgsign-linux-x86_64 --gdwarf-5 ce t -main/dist/gh-gp--no-checkout (dns block)
    • Triggering command: /dependabot-proxy /dependabot-proxy ang/prometheus/prev-parse t ux-amd64/pkg/tool/linux_amd64/compile -W .test t rg/toolchain@v0.0.1-go1.26.1.linux-amd64/pkg/tool/linux_amd64/vet . egator/go-buggre--wait t rg/toolchain@v0.filter -I /smtp/module.go om/prometheus/cl! rg/toolchain@v0.-i --gdwarf-5 s140/hkdf/cast.g/etc/ca-certificates/update.d/ l/linux_amd64/cobr-8684506c92c8 rg/toolchain@v0.-j (dns block)
  • nhooyr.io
    • Triggering command: /dependabot-proxy /dependabot-proxy RETURN mpile 0.1-go1.26.1.linux-amd64/pkg/tool/linux_amd64/vet 2737�� 9e8a34caf7439976049817a4181f4a2d397/config.json ler.go -main/dist/gh-gpgsign/gh-gpgsign-linux-x86_64 --gdwarf-5 ce t -main/dist/gh-gp--no-checkout (dns block)
    • Triggering command: /dependabot-proxy /dependabot-proxy ang/prometheus/prev-parse t ux-amd64/pkg/tool/linux_amd64/compile -W .test t rg/toolchain@v0.0.1-go1.26.1.linux-amd64/pkg/tool/linux_amd64/vet . egator/go-buggre--wait t rg/toolchain@v0.filter -I /smtp/module.go om/prometheus/cl! rg/toolchain@v0.-i --gdwarf-5 s140/hkdf/cast.g/etc/ca-certificates/update.d/ l/linux_amd64/cobr-8684506c92c8 rg/toolchain@v0.-j (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI and others added 2 commits May 12, 2026 06:40
Copilot AI changed the title [WIP] Add SMTP module: API for end-to-end testing SMTP module: Add E2E testing API (search, wait, extract, stats) May 12, 2026
Copilot AI requested a review from butschster May 12, 2026 06:44
@butschster butschster marked this pull request as ready for review May 12, 2026 06:45
@butschster butschster moved this to Done in Buggregator May 12, 2026
@butschster butschster added this to the 2.3 milestone May 12, 2026
@butschster butschster added module: smtp Affects module: smtp area: api Cross-cutting subsystem: api labels May 12, 2026
@butschster butschster merged commit c14027d into master May 12, 2026
2 checks passed
@butschster butschster deleted the copilot/add-smtp-testing-endpoints branch May 12, 2026 14:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: api Cross-cutting subsystem: api module: smtp Affects module: smtp

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[FEATURE] SMTP module: API for end-to-end testing (search, wait, extract)

2 participants