Some checks are pending
Deploy Elmeg / deploy (push) Waiting to run
- Mailgun API as primary email provider - AWS SES kept as fallback - Improved email templates with modern styling - Environment vars: MAILGUN_API_KEY, MAILGUN_DOMAIN
5.5 KiB
5.5 KiB
Mailgun Integration Spec
Date: 2023-12-23
Domain: elmeg.xyz
Purpose: Transactional email (signup, login, password reset, notifications)
Overview
Elmeg will use Mailgun as the transactional email provider instead of AWS SES. Traffic is low-volume and strictly transactional; no marketing or bulk sending.
Account & Domain Setup
1. Mailgun Account
- Create/use shared Mailgun org account owned by Antigravity (not personal)
- Add maintainers with least-privilege roles
2. Domain Configuration
- Sending Domain:
mail.elmeg.xyz(subdomain recommended) - Select appropriate region (US or EU)
3. DNS Records (Cloudflare)
Add the following records as provided by Mailgun:
# SPF
TXT mail.elmeg.xyz "v=spf1 include:mailgun.org ~all"
# DKIM (2 records typically)
TXT smtp._domainkey.mail.elmeg.xyz "k=rsa; p=..."
TXT mailo._domainkey.mail.elmeg.xyz "k=rsa; p=..."
# DMARC
TXT _dmarc.mail.elmeg.xyz "v=DMARC1; p=none; rua=mailto:dmarc@elmeg.xyz"
# MX (for receiving bounces)
MX mail.elmeg.xyz mxa.mailgun.org 10
MX mail.elmeg.xyz mxb.mailgun.org 20
# Tracking (optional)
CNAME email.mail.elmeg.xyz mailgun.org
Wait for Mailgun to show domain as "Verified" before switching production.
Sending Model & Limits
| Aspect | Configuration |
|---|---|
| Plan | Free tier (~100 emails/day), scales to pay-per-use |
| Budget | Well under $10/month for current volume |
| Sending Identity | no-reply@mail.elmeg.xyz for notifications |
| Reply Address | support@elmeg.xyz for human replies |
| Email Types | Account creation, login/OTP, password reset, security alerts |
| Not Allowed | Newsletters, promos, bulk imports |
Application Integration
Environment Variables
# Mailgun API Credentials
MAILGUN_API_KEY=key-xxxxxxxxxxxxxxxxxxxxxxxx
MAILGUN_DOMAIN=mail.elmeg.xyz
MAILGUN_API_BASE=https://api.mailgun.net/v3 # or eu.api.mailgun.net for EU
# Legacy (keep for transition)
EMAIL_FROM=no-reply@mail.elmeg.xyz
# Optional SMTP (if not using API)
MAILGUN_SMTP_HOST=smtp.mailgun.org
MAILGUN_SMTP_PORT=587
MAILGUN_SMTP_LOGIN=postmaster@mail.elmeg.xyz
MAILGUN_SMTP_PASSWORD=xxxxxxxx
Recommended: Use HTTP API
Prefer Mailgun's HTTP API over SMTP for:
- Better error reporting
- Delivery metrics
- Simpler debugging
Code Changes Required
Update backend/services/email.py (or equivalent) to:
import httpx
MAILGUN_API_KEY = os.getenv("MAILGUN_API_KEY")
MAILGUN_DOMAIN = os.getenv("MAILGUN_DOMAIN")
MAILGUN_API_BASE = os.getenv("MAILGUN_API_BASE", "https://api.mailgun.net/v3")
async def send_email(to: str, subject: str, text: str, html: str = None):
"""Send email via Mailgun API"""
async with httpx.AsyncClient() as client:
response = await client.post(
f"{MAILGUN_API_BASE}/{MAILGUN_DOMAIN}/messages",
auth=("api", MAILGUN_API_KEY),
data={
"from": f"Elmeg <no-reply@{MAILGUN_DOMAIN}>",
"to": to,
"subject": subject,
"text": text,
"html": html,
}
)
response.raise_for_status()
return response.json()
Email Templates
Registration/Verification
Subject: Verify your Elmeg account
From: Elmeg <no-reply@mail.elmeg.xyz>
Hi {username},
Welcome to Elmeg! Please verify your email address:
{verification_link}
This link expires in 24 hours.
If you didn't create this account, please ignore this email.
— The Elmeg Team
Password Reset
Subject: Reset your Elmeg password
From: Elmeg <no-reply@mail.elmeg.xyz>
Hi {username},
You requested a password reset. Click below to set a new password:
{reset_link}
This link expires in 1 hour.
If you didn't request this, you can safely ignore this email.
— The Elmeg Team
Deliverability & Monitoring
| Setting | Value |
|---|---|
| Open/Click Tracking | Off (for transactional, reduces complexity) |
| Bounce Handling | Monitor in Mailgun dashboard |
| Target Metrics | <1% bounce rate, <0.1% complaints |
Monitoring Checklist
- Check Mailgun dashboard weekly for delivery rates
- Review any bounces/complaints immediately
- Ramp up gradually if sending volume increases
Migration Steps
Phase 1: Setup (Today)
- Create/access Mailgun account
- Add
mail.elmeg.xyzdomain - Configure DNS in Cloudflare
- Wait for domain verification
Phase 2: Integration
- Add
httpxto requirements.txt - Update email service to use Mailgun API
- Add environment variables to production
.env - Test with a single email before full migration
Phase 3: Switchover
- Remove AWS SES credentials from production
- Update documentation
- Monitor deliverability for first week
Security & Access
| Role | Access |
|---|---|
| Org Owner | Full Mailgun access (Antigravity) |
| Maintainers | Send access, dashboard view |
| DNS | Cloudflare managed by Antigravity |
| Credentials | Environment variables only, never in Git |
Future Considerations
- Marketing Email: If needed, use separate provider (Sendgrid, Postmark) to keep Mailgun clean
- High Volume: If >100/day, upgrade to paid tier
- Webhooks: Mailgun can send delivery/bounce webhooks for advanced tracking
Cost Estimate
| Tier | Volume | Cost |
|---|---|---|
| Free | ~100/day | $0 |
| Flex | Pay per 1,000 | ~$0.80/1,000 |
| Estimated Monthly | ~500 emails | <$1 |