fediversion/docs/MAILGUN_SETUP.md
fullsizemalt b4cddf41ea feat: Initialize Fediversion multi-band platform
- Fork elmeg-demo codebase for multi-band support
- Add data importer infrastructure with base class
- Create band-specific importers:
  - phish.py: Phish.net API v5
  - grateful_dead.py: Grateful Stats API
  - setlistfm.py: Dead & Company, Billy Strings (Setlist.fm)
- Add spec-kit configuration for Gemini
- Update README with supported bands and architecture
2025-12-28 12:39:28 -08:00

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

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)

  1. Create/access Mailgun account
  2. Add mail.elmeg.xyz domain
  3. Configure DNS in Cloudflare
  4. Wait for domain verification

Phase 2: Integration

  1. Add httpx to requirements.txt
  2. Update email service to use Mailgun API
  3. Add environment variables to production .env
  4. Test with a single email before full migration

Phase 3: Switchover

  1. Remove AWS SES credentials from production
  2. Update documentation
  3. 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