A mail catcher in the dev stack, and the accident it prevents

A staging database restored from production contains real addresses, and a queue worker that runs on it sends real email to real customers. It happens to everybody once.

services:
  mail:
    image: mailhog/mailhog
    ports:
      - "8025:8025"     # web UI

# and the application config, in .env.example so it is the default
# MAIL_DRIVER=smtp
# MAIL_HOST=mail
# MAIL_PORT=1025

Putting the catcher in the example environment file rather than in a wiki page is what makes this reliable — the failure mode is a developer copying an old .env, and a default that points at a container which does not exist fails loudly rather than sending. It also makes email testable: the web interface shows the raw message, so an encoding problem in a header is visible rather than reported by a customer. Blocking outbound port 25 at the firewall on non-production hosts is the belt to this brace.