diff --git a/README.md b/README.md index 2567815..7d5afbd 100644 --- a/README.md +++ b/README.md @@ -25,23 +25,25 @@ This repository contains a Symfony 7.3 (PHP >= 8.5.1) application for a collabor - `php bin/console doctrine:migrations:migrate -n` 4. App is at http://localhost:8080 -## Email (Mailpit in dev, SendGrid for prod) +## Email (Mailpit in dev, Mailgun for prod) - Dev: a `mailer` service (Mailpit) runs in Docker. - SMTP DSN in `.env`: `MAILER_DSN=smtp://mailer:1025` - Mailpit UI: http://localhost:8025 (or mapped port 8025) - Send a test mail: `php bin/console app:mail:test you@example.com` -- Staging/Prod: use SendGrid. - - Require package (already in composer): `symfony/sendgrid-mailer`. +- Staging/Prod: use Mailgun. + - Require package (already in composer): `symfony/mailgun-mailer`. - Set environment variables (do NOT commit secrets): - - `MAILER_DSN=sendgrid+api://%env(SENDGRID_API_KEY)%` - - `SENDGRID_API_KEY=YOUR_REAL_KEY` + - `MAILER_DSN=mailgun+api://${MAILGUN_API_KEY}:${MAILGUN_DOMAIN}@default?region=eu` + - `MAILGUN_API_KEY=YOUR_REAL_KEY` + - `MAILGUN_DOMAIN=YOUR_SENDING_DOMAIN` (e.g. `mg.escapepage.nl`) - Optional: `MAILER_FROM=no-reply@your-domain.tld` + - Drop `region=eu` (or use `region=us`) depending on which region your Mailgun domain was created in. - Alternatively via SMTP (no extra package): - - `MAILER_DSN="smtp://apikey:%env(SENDGRID_API_KEY)%@smtp.sendgrid.net:587?encryption=tls"` + - `MAILER_DSN="mailgun+smtp://USERNAME:PASSWORD@default?region=eu"` Troubleshooting: - If emails don’t appear in dev, open Mailpit at http://localhost:8025 and verify messages. -- In prod, check logs for HTTP 2xx responses from SendGrid and verify sender domain is verified in SendGrid. +- In prod, check logs for HTTP 2xx responses from Mailgun and verify sender domain is verified (SPF/DKIM) in Mailgun. ## Frontend assets with Webpack Encore We use Webpack Encore to build and minify JS/CSS from the `assets/` directory into `public/build/`. diff --git a/composer.json b/composer.json index 160a78f..ff3f8e7 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,6 @@ "phpstan/phpdoc-parser": "^2.3.2", "symfony/asset": "7.4.*", "symfony/asset-mapper": "7.4.*", - "symfony/brevo-mailer": "7.4.*", "symfony/console": "7.4.*", "symfony/doctrine-messenger": "7.4.*", "symfony/dotenv": "7.4.*", @@ -27,6 +26,7 @@ "symfony/http-client": "7.4.*", "symfony/intl": "7.4.*", "symfony/mailer": "7.4.*", + "symfony/mailgun-mailer": "7.4.*", "symfony/mercure-bundle": "^0.3.9", "symfony/mime": "7.4.*", "symfony/monolog-bundle": "^3.11.2", diff --git a/doc/email.md b/doc/email.md index 565ae07..596fb7b 100644 --- a/doc/email.md +++ b/doc/email.md @@ -1,9 +1,9 @@ -# Email Delivery: Dev Mailcatcher & Production SendGrid +# Email Delivery: Dev Mailcatcher & Production Mailgun This application uses Symfony Mailer. We separate development and production delivery: - Development: Mailpit (mailcatcher) via SMTP in Docker. -- Production: SendGrid via API transport. +- Production: Mailgun via API transport. ## Development (Mailpit) @@ -22,24 +22,27 @@ MAILER_DSN=smtp://mailer:1025 2. Send an email from the app. 3. Open http://localhost:8025 to view captured emails. -## Production (SendGrid) +## Production (Mailgun) -Use the SendGrid API transport. Do not commit secrets. +Use the Mailgun API transport (`symfony/mailgun-mailer` bridge). Do not commit secrets. - Example configuration is in `.env.prod`: ``` -MAILER_DSN=sendgrid+api://%env(resolve:SENDGRID_API_KEY)%@default +MAILER_DSN=mailgun+api://${MAILGUN_API_KEY}:${MAILGUN_DOMAIN}@default?region=eu ``` -- Provide `SENDGRID_API_KEY` via: - - Real environment variable on the server/container, or - - Symfony secrets: `php bin/console secrets:set SENDGRID_API_KEY` (and dump for prod), or +- `region=eu` is only needed if the Mailgun account/domain was created in Mailgun's EU region (common for `.nl`/EU-based senders). Drop it (or use `region=us`) if the domain lives in the US region. +- Provide `MAILGUN_API_KEY` and `MAILGUN_DOMAIN` via: + - Real environment variables on the server/container, or + - Symfony secrets: `php bin/console secrets:set MAILGUN_API_KEY` (and dump for prod), or - Orchestration secret stores (e.g., Docker/K8s). +- The sending domain must be added and DNS-verified (SPF/DKIM/tracking CNAME) in the Mailgun dashboard before production sending will work reliably; unverified domains are rate-limited/sandboxed. ### Notes - No Mailpit container is defined in the base `compose.yaml`, only in `compose.override.yaml`. This ensures it is used in development only. - To test email locally without Docker, you can: - Run Mailpit on your host (ports 1025/8025) and set `MAILER_DSN=smtp://127.0.0.1:1025` in `.env.local`. -- If you need to use SendGrid SMTP instead of API, a DSN example: - `smtp://apikey:YOUR_SENDGRID_API_KEY@smtp.sendgrid.net:587`. +- If you need to use Mailgun SMTP instead of API, a DSN example: + `mailgun+smtp://USERNAME:PASSWORD@default?region=eu` (username/password come from the Mailgun domain's SMTP credentials). +- Use `php bin/console app:mail:test you@example.com` to send a quick test email against whatever `MAILER_DSN` is currently configured. diff --git a/src/Command/TestEmailCommand.php b/src/Command/TestEmailCommand.php index 891ce77..3e91d6b 100644 --- a/src/Command/TestEmailCommand.php +++ b/src/Command/TestEmailCommand.php @@ -15,7 +15,7 @@ use Symfony\Component\Mime\Email; #[AsCommand( name: 'app:mail:test', - description: 'Sends a simple test email using the configured mail transport (SendGrid in prod).' + description: 'Sends a simple test email using the configured mail transport (Mailgun in prod).' )] final class TestEmailCommand extends Command {