Skip to content

Migrating from Other Email Services

This guide covers migrating from popular email services including SendGrid, Mailgun, Resend, Postmark, and others to mailiam’s unified email infrastructure.

FeaturemailiamSendGridMailgunResendPostmark
ConfigurationYAML configAPI/DashboardAPI/DashboardAPI onlyDashboard
Form HandlingBuilt-inManualManualManualManual
Email ForwardingNativeNot availableBasicNot availableNot available
Spam ProtectionComprehensiveBasicBasicBasicBasic
Pricing ModelSaaS tiersPer emailPer emailPer emailPer email
Developer UXCLI + configAPI integrationAPI integrationAPI integrationDashboard
Template ManagementFile-basedDashboardAPIAPIDashboard
  • Simplified Architecture: One service for forms, forwarding, and sending
  • Better Developer Experience: Configuration as code with Git workflow
  • Cost Effective: Predictable SaaS pricing vs. per-email costs
  • Enhanced Security: Built-in spam protection and rate limiting
  • No Vendor Lock-in: Open configuration format

Document your current setup:

  1. Email Volume: Monthly/daily sending volume
  2. Email Types: Transactional, marketing, forms
  3. Recipients: Internal vs. external email routing
  4. Templates: Custom email templates in use
  5. Integrations: Applications using the current service
  6. Domains: All sending domains configured

Map current features to mailiam equivalents:

Current Featuremailiam Equivalent
Transactional emailsForm submissions + templates
Contact formsBuilt-in form handling
Email forwardingNative forwarding rules
Email templatesYAML-defined templates
WebhooksBuilt-in submission handling
AnalyticsCLI analytics and reports

Typical SendGrid API usage:

const sgMail = require('@sendgrid/mail');
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
const msg = {
to: 'recipient@example.com',
from: 'sender@yourdomain.com',
subject: 'Contact Form Submission',
text: `Name: ${name}\nEmail: ${email}\nMessage: ${message}`,
html: `<strong>Name:</strong> ${name}<br><strong>Email:</strong> ${email}<br><strong>Message:</strong> ${message}`
};
sgMail.send(msg);

mailiam.config.yaml:

project:
name: "My Application"
slug: "my-app"
domains:
yourdomain.com:
forwarding:
"contact@yourdomain.com": "team@company.com"
"notifications@yourdomain.com": "alerts@company.com"
forms:
contact:
name: "Contact Form"
template: "contact-form"
replyTo: "contact@yourdomain.com"
templates:
contact-form:
type: "form"
subject: "Contact Form Submission"
html: |
<div style="font-family: Arial, sans-serif;">
<h2>New Contact Form Submission</h2>
<p><strong>Name:</strong> {{ form.name }}</p>
<p><strong>Email:</strong> {{ form.email }}</p>
<p><strong>Message:</strong></p>
<p>{{ form.message }}</p>
</div>
text: |
Name: {{ form.name }}
Email: {{ form.email }}
Message: {{ form.message }}

Frontend (replaces SendGrid API calls):

<form action="https://api.mailiam.dev/yourdomain.com/contact" method="POST">
<input name="name" placeholder="Name" required>
<input name="email" type="email" placeholder="Email" required>
<textarea name="message" placeholder="Message" required></textarea>
<!-- Spam protection -->
<input type="text" name="_mailiam_honeypot" style="display:none" tabindex="-1" autocomplete="off">
<button type="submit">Send</button>
</form>

SendGrid Dynamic Template:

{
"template_id": "d-abc123",
"personalizations": [
{
"to": [{"email": "recipient@example.com"}],
"dynamic_template_data": {
"name": "{{name}}",
"email": "{{email}}",
"message": "{{message}}"
}
}
],
"from": {"email": "sender@yourdomain.com"}
}

mailiam Template:

templates:
dynamic-contact:
type: "form"
subject: "New message from {{ form.name }}"
html: |
<!DOCTYPE html>
<html>
<head>
<style>
.container { max-width: 600px; font-family: Arial, sans-serif; }
.header { background: #f8f9fa; padding: 20px; text-align: center; }
.content { padding: 20px; }
.footer { background: #e9ecef; padding: 10px; font-size: 12px; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>Contact Form Submission</h1>
</div>
<div class="content">
<p><strong>Name:</strong> {{ form.name }}</p>
<p><strong>Email:</strong> {{ form.email }}</p>
<p><strong>Message:</strong></p>
<blockquote>{{ form.message }}</blockquote>
</div>
<div class="footer">
<p>Sent from {{ domain }} at {{ timestamp }}</p>
</div>
</div>
</body>
</html>

Mailgun API usage:

const mailgun = require('mailgun-js')({
apiKey: process.env.MAILGUN_API_KEY,
domain: 'yourdomain.com'
});
const data = {
from: 'Contact Form <contact@yourdomain.com>',
to: 'team@company.com',
subject: 'Contact Form Submission',
text: `Name: ${name}\nEmail: ${email}\nMessage: ${message}`
};
mailgun.messages().send(data);

Replace with mailiam configuration:

domains:
yourdomain.com:
forwarding:
# Route emails to team
"contact@yourdomain.com": "team@company.com"
"support@yourdomain.com": "support-team@company.com"
forms:
contact:
name: "Contact Form"
replyTo: "contact@yourdomain.com"
template: "mailgun-style"
templates:
mailgun-style:
type: "form"
subject: "Contact Form Submission"
text: |
Name: {{ form.name }}
Email: {{ form.email }}
Message: {{ form.message }}
html: |
<p><strong>Name:</strong> {{ form.name }}</p>
<p><strong>Email:</strong> {{ form.email }}</p>
<p><strong>Message:</strong> {{ form.message }}</p>

Current Mailgun webhook:

app.post('/mailgun/webhook', (req, res) => {
// Process incoming email webhook
const { sender, subject, body } = req.body;
// Forward to internal system
processIncomingEmail(sender, subject, body);
});

mailiam equivalent using email forwarding:

domains:
yourdomain.com:
forwarding:
# Automatic forwarding replaces webhook processing
"webhook@yourdomain.com": "internal-system@company.com"
"*@yourdomain.com": "catch-all@company.com"
# Optional: Process via collections for more control
collections:
webhooks:
name: "Webhook Collection"
settings:
requireApiKey: true
forms:
mailgun-replacement:
email: "internal-system@company.com"

Resend API usage:

import { Resend } from 'resend';
const resend = new Resend('re_123456789');
await resend.emails.send({
from: 'onboarding@yourdomain.com',
to: ['delivered@resend.dev'],
subject: 'Contact Form',
html: '<strong>Contact form submission</strong>',
});

Replace with form-based approach:

domains:
yourdomain.com:
forms:
resend-replacement:
name: "Contact Form"
template: "resend-style"
replyTo: "onboarding@yourdomain.com"
templates:
resend-style:
type: "form"
subject: "Contact Form"
html: |
<div style="font-family: system-ui, sans-serif;">
<h2>Contact Form Submission</h2>
<p><strong>Name:</strong> {{ form.name }}</p>
<p><strong>Email:</strong> {{ form.email }}</p>
<p><strong>Message:</strong></p>
<div style="background: #f6f8fa; padding: 16px; border-radius: 6px;">
{{ form.message | nl2br }}
</div>
</div>

Postmark API usage:

const postmark = require('postmark');
const client = new postmark.ServerClient('your-api-key');
client.sendEmail({
'From': 'sender@yourdomain.com',
'To': 'recipient@example.com',
'Subject': 'Contact form submission',
'HtmlBody': '<strong>Hello</strong> from Postmark!',
'TextBody': 'Hello from Postmark!'
});

Configuration-based approach:

domains:
yourdomain.com:
forms:
postmark-replacement:
name: "Contact Form"
template: "postmark-style"
acknowledgment:
enabled: true
template: "postmark-ack"
templates:
postmark-style:
type: "form"
subject: "Contact form submission"
html: "<strong>Contact Details:</strong><br>{{ form.name }} ({{ form.email }})<br>{{ form.message }}"
text: "Contact Details:\n{{ form.name }} ({{ form.email }})\n{{ form.message }}"
postmark-ack:
type: "acknowledgment"
subject: "Thanks for your message"
html: "<strong>Hello</strong> {{ form.name }}!<br>We received your message and will get back to you soon."
text: "Hello {{ form.name }}!\nWe received your message and will get back to you soon."
  1. Inventory Current Services:

    Terminal window
    # Document all email services in use
    # Map current functionality to mailiam features
    # Identify migration priorities
  2. Set Up mailiam:

    Terminal window
    npm install -g mailiam
    mailiam signup
    mailiam init
  1. Configure Domains:

    domains:
    primary.com:
    forwarding:
    "admin@primary.com": "team@company.com"
    forms:
    contact:
    name: "Primary Contact"
    secondary.com:
    forwarding:
    "*@secondary.com": "catchall@company.com"
  2. Set Up DNS:

    Terminal window
    mailiam domains setup primary.com
    mailiam domains setup secondary.com

Convert templates from all services:

templates:
# From SendGrid template
sendgrid-contact:
type: "form"
subject: "{{ form.subject || 'Contact Form' }}"
html_file: "./templates/sendgrid-style.html"
# From Mailgun template
mailgun-notification:
type: "form"
subject: "Notification: {{ form.type }}"
text: |
Type: {{ form.type }}
Details: {{ form.details }}
# From Resend template
resend-welcome:
type: "acknowledgment"
subject: "Welcome {{ form.name }}"
html_file: "./templates/welcome.html"

Update applications to use mailiam:

Before (multiple services):

// SendGrid for transactional
await sgMail.send(sendGridEmail);
// Mailgun for notifications
await mailgun.messages().send(mailgunData);
// Postmark for marketing
await postmarkClient.sendEmail(postmarkEmail);

After (unified mailiam):

<!-- Single endpoint for all forms -->
<form action="https://api.mailiam.dev/yourdomain.com/unified" method="POST">
<input name="type" value="contact" type="hidden">
<input name="name" placeholder="Name" required>
<input name="email" type="email" placeholder="Email" required>
<textarea name="message" placeholder="Message" required></textarea>
<button type="submit">Send</button>
</form>

If you have multiple domains across different services:

domains:
# Main website (from SendGrid)
company.com:
forwarding:
"hello@company.com": "team@company.com"
forms:
contact:
name: "Main Contact"
# Support portal (from Mailgun)
support.company.com:
forwarding:
"*@support.company.com": "support@company.com"
forms:
ticket:
name: "Support Ticket"
template: "support-ticket"
# Marketing site (from Postmark)
marketing.company.com:
forms:
newsletter:
name: "Newsletter Signup"
template: "newsletter-signup"
acknowledgment:
enabled: true

For high-volume senders:

  1. Gradual Migration:

    settings:
    # Start with higher rate limits
    rate_limit: 100
    domains:
    yourdomain.com:
    forms:
    high-volume:
    rateLimit: 1000 # Higher limits for migration period
  2. Load Testing:

    Terminal window
    # Test with expected volume
    mailiam test send --volume 1000 --duration 1h
  3. Monitoring:

    Terminal window
    # Monitor performance during migration
    mailiam analytics --real-time
Terminal window
# Test each migrated form
curl -X POST https://api.mailiam.dev/yourdomain.com/contact \
-F "name=Migration Test" \
-F "email=test@company.com" \
-F "message=Testing migration from [previous service]"
# Test email forwarding
mailiam test send team@company.com
# Test templates
mailiam templates preview contact-form
Terminal window
# Simulate previous service load
for i in {1..100}; do
curl -X POST https://api.mailiam.dev/yourdomain.com/contact \
-F "name=Load Test $i" \
-F "email=test$i@example.com" \
-F "message=Load testing migration" &
done
wait

Verify all previous functionality works:

  • Email delivery to all recipients
  • Template rendering with dynamic content
  • Rate limiting appropriate for traffic
  • Spam protection enabled
  • Error handling for invalid submissions
  • Analytics and reporting

Take advantage of mailiam’s additional features:

domains:
yourdomain.com:
forms:
enhanced-contact:
# Better spam protection than previous service
spam_protection:
level: "strict"
honeypot: "_bot_trap"
# Reply forwarding (not available in most services)
replies: true
replyTo: "hello@yourdomain.com"
# Advanced rate limiting
rateLimit: 10

Monitor usage and optimize:

Terminal window
# Review usage patterns
mailiam analytics usage --last-month
# Optimize rate limits based on actual traffic
mailiam analytics rate-limits --recommendations

Ensure your team understands the new workflow:

  • Configuration management with Git
  • Deploying changes with mailiam push
  • Monitoring with CLI analytics
  • Troubleshooting common issues
  • Current service inventory completed
  • mailiam account created and CLI installed
  • Domain ownership verified
  • Templates converted to mailiam format
  • Test environment set up
  • DNS records updated for each domain
  • Application code updated to use mailiam
  • Templates deployed and tested
  • Email forwarding rules configured
  • Rate limiting and spam protection configured
  • All functionality tested and verified
  • Previous service integrations removed
  • Previous service subscriptions cancelled
  • Team trained on new workflow
  • Documentation updated
  • Monitoring and alerting set up
  • Migration Consultation: Free consultation for enterprise customers
  • Professional Services: Migration assistance available
  • Documentation: Comprehensive guides for each service
  • Community Support: Discord community for migration questions

Include in your migration request:

  • Current email service(s) used
  • Monthly email volume
  • Number of domains to migrate
  • Timeline requirements
  • Any custom integrations or complex requirements

Migrating to mailiam consolidates your email infrastructure, reduces complexity, and provides better developer experience while maintaining all functionality from your previous services.