# Next.js boilerplate with Mailgun

> Transactional email through Mailgun, behind one provider-agnostic send function. React Email templates are rendered to HTML before sending. Suppression lists are read straight from Mailgun's own API. Mail routes to the EU or US region, and the event webhook is signature-verified.

The veteran sending API. EU data residency and suppression lists kept server-side.

- **Category:** Email
- **Pricing:** Free plan: 100 emails a day and 1 custom domain. Basic starts at $15/month for 10,000 emails. Foundation is $35/month for 50,000 and Scale $90/month for 100,000. Logs are kept 1 day on Free and Basic, 5 days on Foundation and 30 days on Scale.
- **Best for:** Teams that need EU data residency, or want suppression and analytics held by the provider instead of their own database. Also teams sending enough volume to care about dedicated IPs and warm-up support. And the pragmatic choice when an existing system already speaks Mailgun.
- **Conflicts with:** resend
- **Vendor docs:** https://documentation.mailgun.com/docs/mailgun/user-manual/get-started/

## Trade-offs

- Region is chosen when the domain is created and cannot change. An EU domain must use api.eu.mailgun.net. The US host returns a 401 that reads like a bad key.
- The API is form-encoded, not JSON, which is why the SDK needs form-data as a peer. It is an older API and it shows in places.
- No React rendering on Mailgun's side. Templates are rendered to HTML in your app before sending. Mailgun's own templates are Handlebars stored in the dashboard, a different workflow this battery does not use.
- No built-in idempotency key. A retried job can send twice unless you deduplicate, so this battery attaches a deterministic Message-Id and a custom variable.
- Suppression lists live in Mailgun and are queryable through the API. No local table to maintain and one less thing to keep in sync.

## Known fixes it ships

- [Mailgun returns 401 and your API key is fine: the EU/US region trap](https://agenticboilerplate.com/cookbook/mailgun/eu-vs-us-region-endpoints): A Mailgun domain lives in the region it was created in. Calling the wrong regional host returns 401 Unauthorized, which reads exactly like a bad API key.
- [Mailgun says the message was queued and nobody receives it: sandbox domain limits](https://agenticboilerplate.com/cookbook/mailgun/sandbox-domain-limits): The sandbox domain accepts every send and delivers only to five addresses you authorised. Recognise it, use it deliberately, and know when to stop.
- [Suppression lists in Mailgun: stop maintaining your own bounce table](https://agenticboilerplate.com/cookbook/mailgun/suppression-lists): Mailgun stores bounces, complaints and unsubscribes per domain and refuses to send to them. Read that list instead of building a table you have to keep in sync.
- [Mailgun templates and recipient variables versus rendering HTML in your app](https://agenticboilerplate.com/cookbook/mailgun/template-variables-vs-rendered-html): Mailgun stores Handlebars templates in its dashboard and substitutes variables at send time. Rendering in your app instead keeps email in code review: here is when each one wins.
- [Open tracking, click tracking and why they are off by default](https://agenticboilerplate.com/cookbook/mailgun/tracking-pixels-and-privacy): Mailgun's tracking adds a pixel and rewrites every link. Both are personal data under GDPR, both cost deliverability, and neither belongs on a magic link.

## Generate it

[Build a repo with Mailgun](https://agenticboilerplate.com/build?b=mailgun)

---

Agentic Boilerplate: A Next.js repo your agent already knows. Free during launch, then $99 once.

- Site map for agents: https://agenticboilerplate.com/llms.txt
- Public API: https://agenticboilerplate.com/openapi.json
- Contact: agenticstudio@gmail.com
