If you’ve ever tried to send receipts, password resets, or welcome emails by hand, you know it gets old fast. Even if you’re using an email marketing tool, odds are it’s not built for one-off, time-sensitive messages. This guide is for developers and ops folks who want to automate transactional emails right—using the Mailgun API.
No fluff, no marketing hype—just the real steps, pitfalls, and a few code samples you can actually use.
Why automate transactional emails with an API?
Let's get this out of the way: you could send emails from your own server. But unless you love managing spam complaints, deliverability issues, and random outages, it's not worth it. Transactional emails (like order confirmations, alerts, or password resets) have to arrive fast and reliably. APIs like Mailgun are built exactly for this, so you can focus on your app, not email headaches.
Step 1: Get set up with Mailgun
First, you’ll need a Mailgun account. Sign up, verify your domain, and grab your API key.
What to skip: Don’t waste time configuring every setting in the dashboard. Focus on:
- Domain verification: Your emails will look sketchy and probably land in spam if you skip this.
- API keys: Keep these secret. Don’t hardcode them in public repos—use environment variables.
Pro tip: Start with a sandbox domain for testing. Mailgun limits who you can send to in sandbox mode, but it’s safer for dev work.
Step 2: Pick your workflow triggers
Before you touch code, map out when transactional emails should go out. Typical triggers:
- New user signs up → Send welcome email
- User requests password reset → Send reset link
- Order is placed → Send receipt
Be specific. Don’t try to cram all emails into one “catch-all” handler. It’ll be a pain to debug later.
Step 3: Write the code to send emails
Mailgun has SDKs for popular languages. Here’s a no-nonsense example in Python using their official library:
python import os from mailgun import Mailgun
MAILGUN_DOMAIN = os.environ['MAILGUN_DOMAIN'] MAILGUN_API_KEY = os.environ['MAILGUN_API_KEY']
mg = Mailgun(domain=MAILGUN_DOMAIN, api_key=MAILGUN_API_KEY)
def send_welcome_email(to_email, user_name): subject = "Welcome!" text = f"Hi {user_name}, thanks for signing up." mg.send_message( from_email=f"YourApp noreply@{MAILGUN_DOMAIN}", to_emails=[to_email], subject=subject, text=text )
What works:
- Use environment variables for secrets.
- Keep your templates separate from code (more on this below).
What to ignore:
- Don’t reinvent the wheel with raw SMTP. The API is simpler and handles more edge cases.
Other languages:
Mailgun has libraries for Node.js, PHP, Java, and more. The calls are all pretty similar; check their docs if you’re not using Python.
Step 4: Use email templates (and keep them simple)
Hardcoding email bodies in your code is tempting, but it’s a mess to update later. Mailgun lets you create and store templates in their dashboard.
How to use templates:
- Log into Mailgun and create a template (e.g., “welcome_email”).
- Use variables like
{{user_name}}
in the template. - Call the template from your code:
python mg.send_message( from_email=f"YourApp noreply@{MAILGUN_DOMAIN}", to_emails=[to_email], subject="Welcome!", template="welcome_email", template_variables={"user_name": user_name} )
What works:
- Templates make it easy for non-devs to tweak messaging.
- Keeps your codebase clean.
What doesn’t:
- Overly fancy templates with lots of images or CSS. They’re more likely to go to spam or break in email clients. Stick to simple HTML and plain text.
Step 5: Handle errors and bounces
It’s easy to forget: just because your code says “email sent” doesn’t mean it landed in someone’s inbox. Mailgun gives you webhooks for delivery events.
Set up webhooks for:
- Delivered
- Bounced
- Complaints
- Unsubscribes (if relevant)
How to use:
Create endpoints in your app to receive POST requests from Mailgun. Log or alert on failures, so you don’t miss silent errors.
Honest take:
Don’t obsess over every bounce or complaint, but do track patterns. If you suddenly see a surge, something’s broken.
Step 6: Test, test, test
Send test emails to different providers (Gmail, Outlook, Yahoo). Check:
- Did it arrive?
- Did it go to spam?
- Does it look right on mobile?
What to ignore:
- Don’t trust the “Test” button in Mailgun alone. Real-world inboxes behave differently.
Pro tip:
Use tools like MailTester to check spam scores.
Step 7: Automate recurring workflows
If you’re sending the same type of transactional email regularly, automate it:
- Password resets: Triggered by user action, not a cron job.
- Daily digests or summaries: Use a scheduled task in your backend to pull data and send via Mailgun.
Keep the automation logic in your app, not in Mailgun. Mailgun sends emails; your app decides when.
Security and compliance basics
A few things you can’t ignore:
- Don’t send sensitive info in plain email. Passwords, tokens, or anything private should be links, not raw data.
- Honor unsubscribe and legal requirements. For receipts or alerts, you may not need unsubscribe links, but for anything else, add them.
- Stay off blocklists. Don’t use Mailgun for bulk marketing from the same domain as your transactional emails. That’s a quick way to hurt deliverability.
Common gotchas (and how to avoid them)
- Sandbox domains won’t send to everyone. Good for dev, not for prod.
- SPF/DKIM not set up? Your emails will go to spam. Do this early.
- Forgetting about rate limits. If you’re sending a ton of emails at once, check Mailgun’s limits or you’ll get errors.
- Testing with real users. Never do it. Use test accounts and your own email for QA.
When Mailgun isn’t enough
Mailgun’s great for developers, but:
- No built-in visual workflow builder. If you want “if user clicks X, send Y,” you’ll need to code that logic.
- Limited analytics. You get delivery stats, but not the in-depth reporting some marketers want.
- Pricing: It’s pay-as-you-go, and it adds up if you’re sending millions of emails. Don't ignore this if your app scales.
If you need more automation or drag-and-drop tools, look at alternatives like SendGrid or Postmark. But for straight-up transactional emails, Mailgun’s tough to beat.
Keep it simple (and iterate)
You don’t need a massive system to automate transactional emails. Start with Mailgun’s API, keep your workflows straightforward, and build from there. Don’t overcomplicate things—just get your emails delivered and worry about bells and whistles later.
The goal: emails that arrive fast, look clean, and don’t get you blacklisted. That’s it. Start small, test as you go, and you’ll save yourself a ton of headaches.