Enterprise-grade multi-account email management with smart routing, OAuth 2.0 support, and complete security compliance
Stop fighting with .env files and email configuration! MagicMail brings enterprise email management to Strapi v5 with:
- ✅ 6 Email Providers - Gmail, Microsoft 365, Yahoo, SMTP, SendGrid, Mailgun
- ✅ OAuth 2.0 Authentication - No passwords needed for Gmail, Microsoft, Yahoo
- ✅ Smart Routing Rules - Route emails by type, recipient, subject, or custom conditions
- ✅ Automatic Failover - Never lose an email when rate limits hit
- ✅ Beautiful Admin UI - Manage everything from Strapi Admin Panel
- ✅ Zero Configuration - No .env files, everything in the database
- ✅ Email Designer Compatible - Works seamlessly with strapi-plugin-email-designer-5
- ✅ GDPR/CAN-SPAM Compliant - Built-in List-Unsubscribe headers
- ✅ Enterprise Security - TLS 1.2+, DKIM, SPF, DMARC validation
Manage unlimited email accounts with live stats and real-time monitoring
Choose from 6 different email providers with OAuth 2.0 support
Configure SMTP settings or connect with OAuth
Complete setup with rate limits and test connection
Create and manage email templates with the visual designer
Drag-and-drop email editor with real-time preview
Track changes and restore previous template versions (ADVANCED+)
Test your templates before sending to production
Define intelligent routing rules based on email type, recipient, subject
Track email performance with detailed analytics and statistics
Simple API integration with your Strapi application
npm install strapi-plugin-magic-mail
# or
yarn add strapi-plugin-magic-mailCreate or update config/plugins.ts:
export default () => ({
'magic-mail': {
enabled: true,
},
});npm run build
npm run develop- Navigate to Admin Panel → MagicMail → Email Accounts
- Click "Add Account"
- Choose your provider (Gmail OAuth, SMTP, etc.)
- Fill in credentials
- Click "Test" to verify
- Done! 🎉
| Provider | Type | Authentication | Features |
|---|---|---|---|
| Gmail | OAuth 2.0 | Google OAuth | Gmail API, Attachments, Auto DKIM |
| Microsoft 365 | OAuth 2.0 | Azure AD | Graph API, Attachments, Tenant Support |
| Yahoo Mail | OAuth 2.0 | Yahoo OAuth | SMTP OAuth2, Attachments |
| SMTP | Credentials | Username/Password | Universal, DKIM Optional, Custom Servers |
| SendGrid | API Key | SendGrid API | Transactional, Marketing, Templates |
| Mailgun | API Key | Mailgun API | Bulk Sending, Analytics |
MagicMail automatically intercepts Strapi's email service - no code changes needed!
// This works in ANY Strapi plugin or controller:
await strapi.plugin('email').service('email').send({
to: 'user@example.com',
subject: 'Welcome to Our Platform!',
text: 'Plain text version',
html: '<h1>Welcome!</h1><p>Thanks for signing up!</p>',
});
// ✅ MagicMail automatically:
// - Selects best account (via routing rules or priority)
// - Checks rate limits
// - Handles failover if needed
// - Logs the email
// - Updates statisticsBenefits:
- ✅ Zero code changes - Existing plugins work automatically
- ✅ Email Designer compatible - Works with strapi-plugin-email-designer-5
- ✅ Fallback safe - Falls back to original email service if MagicMail fails
- ✅ Drop-in replacement - Just enable and go!
For explicit control over account selection:
// Force a specific account
await strapi.plugin('magic-mail').service('email-router').send({
to: 'customer@example.com',
subject: 'Order Confirmation',
html: '<h1>Your Order #12345</h1>',
accountName: 'SendGrid Marketing', // Force this account
type: 'transactional',
priority: 'high',
});await strapi.plugin('email').service('email').send({
to: 'customer@example.com',
subject: 'Invoice #12345',
html: '<h1>Invoice Attached</h1>',
attachments: [
{
filename: 'invoice.pdf',
path: './uploads/invoice-12345.pdf',
},
{
filename: 'receipt.pdf',
content: Buffer.from(pdfData),
contentType: 'application/pdf',
},
],
});Supported attachment formats:
- ✅ PDF, Word, Excel, PowerPoint
- ✅ Images (PNG, JPG, GIF, WebP)
- ✅ Text files (TXT, CSV, JSON)
- ✅ Archives (ZIP, RAR)
- ✅ Any file type!
// High priority email
await strapi.plugin('magic-mail').service('email-router').send({
to: 'vip@example.com',
subject: 'Urgent: Action Required',
html: '<h1>Important Update</h1>',
priority: 'high', // Adds X-Priority and Importance headers
});
// Marketing email with unsubscribe (GDPR/CAN-SPAM compliant)
await strapi.plugin('magic-mail').service('email-router').send({
to: 'subscriber@example.com',
subject: 'Weekly Newsletter',
html: '<h1>This Week's Updates</h1>',
type: 'marketing',
unsubscribeUrl: 'https://yoursite.com/unsubscribe?id=123',
// Automatically adds List-Unsubscribe header!
});Design beautiful emails visually with the integrated email designer!
| Feature | FREE | PREMIUM | ADVANCED | ENTERPRISE |
|---|---|---|---|---|
| Visual Designer | ✅ Basic builder | ✅ + template library | ✅ Pro components | ✅ Enterprise suite |
| Templates Included | 25 | 100 | 500 | Unlimited |
| Drag & Drop + Mustache | ✅ | ✅ | ✅ | ✅ |
| Import / Export | ✅ | ✅ | ✅ | ✅ |
| Template Versioning | ❌ | ✅ | ✅ | ✅ |
| Analytics | ❌ | Basic insights | Advanced dashboard | Enterprise analytics |
| Custom Blocks | ❌ | ❌ | ❌ | ✅ |
| Team Library | ❌ | ❌ | ❌ | ✅ |
| A/B Testing | ❌ | ❌ | ❌ | ✅ |
1. Navigate to Email Templates Tab
Go to MagicMail → Email Templates in the admin panel.
2. Create New Template
Click "Create Template" and use the visual designer to build your email.
3. Add Variables with Mustache
Use Mustache syntax for dynamic content:
<h1>Welcome {{user.firstName}}!</h1>
<p>Thanks for joining {{company.name}}</p>4. Save & Use
Each template gets a unique Reference ID (e.g., 100) that you use when sending.
Method 1: Using Template ID
// Send email using template
await strapi.plugin('magic-mail').service('email-router').send({
to: 'user@example.com',
templateId: 100, // Your template reference ID
templateData: {
user: {
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
},
company: {
name: 'ACME Corp',
url: 'https://acme.com',
},
orderNumber: '12345',
orderTotal: '$199.99',
},
});
// ✅ MagicMail will:
// - Load template #100
// - Render it with your data (Mustache)
// - Route via smart routing
// - Send via best accountMethod 2: Via Strapi Email Service
// Also works with standard Strapi email service!
await strapi.plugin('email').service('email').send({
to: 'user@example.com',
templateId: 100,
templateData: {
user: { firstName: 'Jane' },
resetUrl: 'https://yoursite.com/reset?token=xyz',
},
});Templates can be categorized for automatic routing:
- transactional - Order confirmations, receipts
- marketing - Newsletters, promotions
- notification - System alerts, updates
- custom - Anything else
Automatic Routing by Category:
// Create routing rule: All marketing templates → SendGrid
// Then just send:
await strapi.plugin('magic-mail').service('email-router').send({
to: 'subscriber@example.com',
templateId: 200, // Marketing category template
templateData: { offer: '50% OFF' },
});
// ✅ Automatically routes via SendGrid (based on category)Every time you save a template, a new version is created automatically:
// Get all versions
const versions = await strapi
.plugin('magic-mail')
.service('email-designer')
.getVersions(templateId);
// Restore old version
await strapi
.plugin('magic-mail')
.service('email-designer')
.restoreVersion(templateId, versionId);Export all templates:
const templates = await strapi
.plugin('magic-mail')
.service('email-designer')
.exportTemplates();
// Save to file
fs.writeFileSync('templates.json', JSON.stringify(templates, null, 2));Import templates:
const templates = JSON.parse(fs.readFileSync('templates.json'));
const results = await strapi
.plugin('magic-mail')
.service('email-designer')
.importTemplates(templates);
console.log(`Imported ${results.filter(r => r.success).length} templates`);Powered by Unlayer Email Editor:
- ✅ Drag & Drop Interface
- ✅ Pre-built Content Blocks
- ✅ Image Upload & Management
- ✅ Custom Fonts & Colors
- ✅ Responsive Design
- ✅ Mobile Preview
- ✅ HTML/Text Editor
- ✅ Merge Tags Support
- ✅ Save/Load Designs
const stats = await strapi
.plugin('magic-mail')
.service('email-designer')
.getStats();
console.log(stats);
// {
// total: 15,
// active: 12,
// inactive: 3,
// byCategory: [
// { category: 'transactional', count: 8 },
// { category: 'marketing', count: 4 },
// { category: 'notification', count: 3 }
// ],
// maxTemplates: 3, // FREE tier limit
// remaining: 0 // Upgrade needed!
// }1. Use Template Categories
// Set category when creating template
category: 'marketing' // Auto-routes to marketing account2. Test Templates Before Using
// Test render before sending
const rendered = await strapi
.plugin('magic-mail')
.service('email-designer')
.renderTemplate(100, { user: { firstName: 'Test' } });
console.log(rendered.html); // Preview HTML3. Version Control
// ADVANCED+: Keep version history
// Automatically enabled for ADVANCED and ENTERPRISE licenses4. Organize with Tags
// Add tags to templates
tags: ['onboarding', 'welcome-series', 'v2']Create intelligent routing rules to send emails through specific accounts based on conditions.
1. Route Marketing Emails via SendGrid:
Match Type: Email Type
Match Value: marketing
Target Account: SendGrid Marketing
Priority: 10
2. Route VIP Customers via Premium SMTP:
Match Type: Recipient
Match Value: @vip-customers.com
Target Account: Premium SMTP
Fallback Account: Gmail OAuth
Priority: 9
3. Route Password Reset Emails:
Match Type: Subject
Match Value: Password Reset
Target Account: Transactional SMTP
Priority: 8
Rules are evaluated from highest to lowest priority (1-10):
- Priority 10 = Evaluated first (most specific rules)
- Priority 1 = Evaluated last (catch-all rules)
If no rule matches, the Primary Account is used.
1. Google Cloud Console
- Go to console.cloud.google.com
- Create a new project or select existing
- Enable Gmail API
- Create OAuth 2.0 Client ID
- Add redirect URI:
http://localhost:1337/magic-mail/oauth/gmail/callback - Copy Client ID and Client Secret
2. In MagicMail
- Choose "Gmail OAuth" provider
- Paste Client ID and Client Secret
- Click "Connect with Google"
- Authorize in popup
- Done! ✅
Required Scopes:
https://www.googleapis.com/auth/gmail.sendhttps://www.googleapis.com/auth/userinfo.email
1. Azure Portal
- Go to portal.azure.com
- Navigate to Azure Active Directory → App registrations
- Click "New registration"
- Name: "MagicMail"
- Account type: "Accounts in this organizational directory only"
- Copy Application (client) ID AND Directory (tenant) ID
2. Add Redirect URI
http://localhost:1337/magic-mail/oauth/microsoft/callback
3. API Permissions
Add these Delegated permissions under Microsoft Graph:
- ✅
Mail.Send- Send emails as the signed-in user - ✅
User.Read- Read user profile - ✅
offline_access- Maintain access (refresh tokens) - ✅
openid- Sign users in - ✅
email- View users' email address
4. Grant Admin Consent (Required!)
5. Create Client Secret
- Certificates & secrets → New client secret
- Copy the VALUE (not the Secret ID)
- Store it securely!
6. In MagicMail
- Choose "Microsoft OAuth" provider
- Paste Tenant ID, Client ID, and Client Secret
- Click "Connect with Microsoft"
- Authorize
- Done! ✅
1. Yahoo Developer Console
- Go to developer.yahoo.com/apps
- Click "Create an App"
- Fill in app details
2. Add Redirect URI
http://localhost:1337/magic-mail/oauth/yahoo/callback
3. API Permissions
- ✅
Mail- Send and manage emails - ✅
OpenID Connect- User authentication
4. In MagicMail
- Choose "Yahoo Mail OAuth" provider
- Paste Client ID and Client Secret
- Click "Connect with Yahoo"
- Done! ✅
Works with ANY SMTP server:
Host: smtp.gmail.com (or your SMTP server)
Port: 587 (STARTTLS) or 465 (SSL/TLS)
Username: your-email@domain.com
Password: your-password (or App Password)
Popular SMTP Servers:
- Gmail:
smtp.gmail.com:587(use App Password!) - Outlook:
smtp-mail.outlook.com:587 - Office365:
smtp.office365.com:587 - Custom: Your own mail server
Gmail App Password:
- Google Account → Security → 2-Step Verification
- App passwords → Generate
- Use the 16-character password in MagicMail
Optional: DKIM Signing
For custom domains, you can add DKIM:
// In config field (advanced users):
{
dkim: {
domainName: 'yourdomain.com',
keySelector: 'default',
privateKey: '-----BEGIN PRIVATE KEY-----\n...'
}
}1. Get API Key
- Go to app.sendgrid.com
- Settings → API Keys → Create API Key
- Scope: Mail Send (Full Access)
- Copy the API key
2. In MagicMail
- Choose "SendGrid" provider
- Paste API Key
- Done! ✅
1. Get API Key & Domain
- Go to app.mailgun.com
- Settings → API Security → Copy Private API Key
- Sending → Domains → Copy your verified domain
2. In MagicMail
- Choose "Mailgun" provider
- Enter Domain (e.g.,
mg.yourdomain.com) - Paste Private API Key
- Done! ✅
- ✅ AES-256-GCM encryption for all credentials
- ✅ No plain text passwords in database
- ✅ OAuth tokens encrypted at rest
- ✅ Secure token refresh mechanism
- ✅ TLS 1.2+ enforced (SMTP)
- ✅ Certificate verification enabled
- ✅ HTTPS only for API providers
- ✅ DKIM signing (optional for SMTP, automatic for OAuth)
- ✅ SPF validation support
- ✅ DMARC compliance - All providers pass DMARC checks
- ✅ Proper Message-ID generation (RFC 5322)
- ✅ XSS prevention - No
<script>tags allowed - ✅ Input validation - Email format, subject length
- ✅ Spam trigger detection - Warns about suspicious patterns
- ✅ MIME type validation
- ✅ List-Unsubscribe (RFC 8058) - GDPR/CAN-SPAM compliant
- ✅ Auto-Submitted (RFC 3834) - Prevents auto-responder loops
- ✅ Precedence: bulk for marketing emails
- ✅ X-Priority and Importance headers
- Unlimited email accounts
- Provider-specific configuration
- Active/Inactive status
- Primary account designation
- Per-account priority (1-10)
- Daily and hourly rate limits
- Email Type Routing - transactional, marketing, notification
- Recipient Matching - Route by email domain or address
- Subject Matching - Route by subject keywords
- Template Matching - Route by template name
- Custom Field Matching - Flexible custom conditions
- Priority-based evaluation - Higher priority rules match first
- Fallback accounts - Automatic failover per rule
- Per-account daily limits
- Per-account hourly limits
- Automatic counter reset (hourly/daily)
- Smart failover to backup accounts
- Rate limit hit detection
- Account health monitoring
- Real-time statistics dashboard
- Emails sent today (per account and total)
- Total emails sent (lifetime)
- Active/Inactive account count
- Success/Failure tracking
- Last used timestamps
- Visual progress bars for rate limits
- Test Direct - Test specific account directly
- Test Strapi Service - Verify Email Designer compatibility
- Priority Testing - Test high/normal priority headers
- Marketing Email Testing - Test List-Unsubscribe headers
- Detailed test results - Shows all security features applied
All configuration is done via the Admin Panel. However, for production deployments, you can set:
# Optional - Base URL for OAuth callbacks
URL=https://yourdomain.com
# Optional - Encryption key (auto-generated if not provided)
ENCRYPTION_KEY=your-32-character-secret-keyEach account can have:
Basic Settings:
- Name (unique identifier)
- Description
- Provider type
- From Email
- From Name
- Reply-To Email
Security:
- OAuth credentials (encrypted)
- SMTP credentials (encrypted)
- API keys (encrypted)
- DKIM configuration (optional)
Rate Limiting:
- Daily email limit (0 = unlimited)
- Hourly email limit (0 = unlimited)
- Priority (1-10, higher = preferred)
Status:
- Active/Inactive
- Primary account designation
await strapi.plugin('email').service('email').send({
to: 'recipient@example.com',
from: 'sender@example.com', // Optional - uses account default
subject: 'Email Subject',
text: 'Plain text content',
html: '<h1>HTML content</h1>',
// Optional advanced options:
replyTo: 'reply@example.com',
type: 'transactional', // or 'marketing', 'notification'
priority: 'normal', // or 'high'
accountName: 'Specific Account', // Force specific account
unsubscribeUrl: 'https://site.com/unsubscribe', // For marketing emails
attachments: [
{
filename: 'document.pdf',
path: './path/to/file.pdf',
contentType: 'application/pdf',
},
],
});await strapi.plugin('magic-mail').service('email-router').send({
to: 'user@example.com',
subject: 'Test Email',
html: '<p>Content</p>',
accountName: 'Gmail OAuth', // Optional - force specific account
type: 'transactional',
priority: 'normal',
});const accounts = await strapi.plugin('magic-mail').service('account-manager').getAllAccounts();const result = await strapi.plugin('magic-mail').service('account-manager').testAccount(
accountId,
'test@example.com',
{
priority: 'high',
type: 'marketing',
unsubscribeUrl: 'https://example.com/unsubscribe',
}
);- Go to Email Accounts
- Click Test button on any account
- Enter recipient email
- Select test options:
- Priority: Normal / High
- Email Type: Transactional / Marketing / Notification
- Unsubscribe URL: (for marketing emails)
- Choose test method:
- Test Direct - Direct send via account
- Test Strapi Service - Via Strapi email service (tests Email Designer compatibility)
// Test email with all security features
await strapi.plugin('magic-mail').service('account-manager').testAccount(
accountId,
'your-email@example.com',
{
priority: 'high',
type: 'marketing',
unsubscribeUrl: 'https://yoursite.com/unsubscribe',
}
);To verify security headers are applied:
In Gmail:
- Open email → Click ⋮ (three dots)
- "Show original"
- Look for:
X-Mailer: MagicMail/1.0 X-Priority: 1 (Highest) Importance: high List-Unsubscribe: <https://...> Message-ID: <...> DKIM-Signature: ...
In Outlook/Microsoft:
- Email → File → Properties
- View "Internet headers"
- Should show "High Importance" with red exclamation mark
| Standard | Status | Description |
|---|---|---|
| DKIM | ✅ | DomainKeys Identified Mail - Signature validation |
| SPF | ✅ | Sender Policy Framework - Sender verification |
| DMARC | ✅ | Domain-based Authentication - Policy enforcement |
| TLS 1.2+ | ✅ | Transport Layer Security - Encrypted transmission |
| AES-256-GCM | ✅ | Credential encryption at rest |
| Regulation | Status | Implementation |
|---|---|---|
| GDPR | ✅ | List-Unsubscribe header for marketing emails |
| CAN-SPAM | ✅ | One-click unsubscribe mechanism (RFC 8058) |
| RFC 5322 | ✅ | Proper email format and headers |
| RFC 3834 | ✅ | Auto-Submitted header prevents loops |
| RFC 2156 | ✅ | Priority and Importance headers |
Every email is validated for:
- ✅ Valid recipient email format
- ✅ Non-empty subject line
- ✅ Subject length (warns if > 200 chars)
- ✅ Content presence (text or html required)
- ✅ No
<script>tags in HTML - ✅ No
javascript:protocol in links - ✅ Spam trigger detection (warns only)
Global Stats:
- Emails sent today (all accounts)
- Total emails sent (lifetime)
- Active accounts count
Per-Account Stats:
- Emails sent today
- Total emails sent
- Rate limit usage (visual progress bars)
- Last used timestamp
- Success/failure rate
Every email is logged with:
- Recipient
- Sender
- Subject
- Account used
- Status (sent/failed)
- Timestamp
- Email type
- Error message (if failed)
Access logs via:
const logs = await strapi.entityService.findMany('plugin::magic-mail.email-log', {
filters: { status: 'sent' },
sort: { createdAt: 'desc' },
limit: 100,
});MagicMail is fully compatible with strapi-plugin-email-designer-5!
-
Install Email Designer:
npm install strapi-plugin-email-designer-5
-
Create email templates in Email Designer
-
Send via template:
// Email Designer internally uses strapi.plugin('email').service('email').send() // MagicMail automatically intercepts it!
-
Your email is automatically:
- ✅ Routed through MagicMail's smart routing
- ✅ Sent via the best account (based on rules)
- ✅ Rate limited and failover protected
- ✅ Logged and tracked
No configuration needed - it just works! 🎉
1. Check Logs
# Look for errors in Strapi console
[magic-mail] ❌ Email send failed: ...2. Check Account Status
- Is the account marked as "Active"?
- Test the account using the Test button
- Check rate limits haven't been exceeded
3. Check Spam Folder
- First emails from new accounts may land in spam
- Check spam/junk folders
- Mark as "Not Spam" to train filters
4. Verify Credentials
- SMTP: Username and password correct?
- Gmail: Using App Password (not regular password)?
- OAuth: Tokens may have expired - reconnect
For Custom Domains:
-
Set up SPF record:
v=spf1 include:_spf.google.com ~all -
Set up DKIM:
- Generate DKIM key pair
- Add public key to DNS
- Add private key to MagicMail SMTP config
-
Set up DMARC:
v=DMARC1; p=quarantine; rua=mailto:dmarc@yourdomain.com
For OAuth Providers (Gmail, Microsoft, Yahoo):
- ✅ DKIM handled automatically
- ✅ SPF handled automatically
- ✅ DMARC should pass automatically
If you hit rate limits:
- Increase daily/hourly limits in account settings
- Add more accounts for load balancing
- Set up routing rules to distribute load
- Check provider-specific limits:
- Gmail: 500/day (free), 2000/day (workspace)
- SendGrid: Varies by plan
- Mailgun: Varies by plan
Gmail OAuth:
- Ensure Gmail API is enabled
- Check redirect URI matches exactly
- Clear browser cookies and try again
Microsoft OAuth:
- Verify all 5 permissions are granted
- Grant admin consent (required!)
- Use correct Tenant ID
- Check Client Secret hasn't expired
Yahoo OAuth:
- Verify app is approved by Yahoo
- Check API permissions are enabled
magic-mail/
├── admin/ # React Admin UI
│ └── src/
│ ├── components/
│ │ ├── AddAccountModal.jsx # Multi-step account setup
│ │ └── PluginIcon.jsx # Sidebar icon
│ └── pages/
│ ├── App.jsx # Main app with tabs
│ ├── HomePage.jsx # Email accounts page
│ └── RoutingRules.jsx # Routing rules page
├── server/ # Backend
│ └── src/
│ ├── bootstrap.js # Overrides Strapi email service
│ ├── controllers/
│ │ ├── accounts.js # CRUD for accounts
│ │ ├── oauth.js # OAuth flows
│ │ └── routing-rules.js # CRUD for routing rules
│ ├── services/
│ │ ├── email-router.js # Core routing logic
│ │ ├── account-manager.js # Account management
│ │ └── oauth.js # OAuth token exchange
│ ├── content-types/
│ │ ├── email-account/ # Account schema
│ │ ├── email-log/ # Email log schema
│ │ └── routing-rule/ # Routing rule schema
│ └── utils/
│ └── encryption.js # AES-256-GCM encryption
└── package.json
Email Request
↓
Strapi Email Service (intercepted!)
↓
MagicMail Email Router
↓
Routing Rules Engine
↓
Account Selection (priority/rules)
↓
Rate Limit Check
↓
Provider-Specific Sender
↓
Email Log & Stats Update
↓
Response
// Each tenant gets their own email account
// Route by custom field:
// Routing Rule:
// Match Type: Custom Field
// Match Value: tenant-123
// Target Account: Tenant 123 Gmail
await strapi.plugin('email').service('email').send({
to: 'customer@example.com',
subject: 'Order Confirmation',
html: '<h1>Order #456</h1>',
customField: 'tenant-123', // Matches routing rule
});// Distribute load across multiple accounts
// Account 1: Priority 10, Limit 500/day
// Account 2: Priority 9, Limit 500/day
// Account 3: Priority 8, Limit 500/day
// → Total: 1500 emails/day with automatic load balancing!// Route marketing emails via SendGrid
// Routing Rule:
// Match Type: Email Type
// Match Value: marketing
// Target Account: SendGrid Marketing
await strapi.plugin('email').service('email').send({
to: 'subscriber@example.com',
subject: 'Weekly Newsletter',
html: template,
type: 'marketing',
unsubscribeUrl: 'https://yoursite.com/unsubscribe?id=123',
});
// ✅ Automatically routes via SendGrid
// ✅ Adds List-Unsubscribe header
// ✅ GDPR/CAN-SPAM compliant// Route VIP customers via premium account
// Routing Rule:
// Match Type: Recipient
// Match Value: @vip-domain.com
// Target Account: Premium SMTP
// Fallback Account: Gmail OAuth
await strapi.plugin('email').service('email').send({
to: 'ceo@vip-domain.com',
subject: 'Exclusive Offer',
html: content,
priority: 'high',
});
// ✅ Routes via Premium SMTP
// ✅ High priority headers added
// ✅ Automatic fallback if premium account unavailable| Feature | Gmail OAuth | Microsoft OAuth | Yahoo OAuth | SMTP | SendGrid | Mailgun |
|---|---|---|---|---|---|---|
| Auth Method | OAuth 2.0 | OAuth 2.0 | OAuth 2.0 | Password | API Key | API Key |
| Free Tier | 500/day | Varies | Limited | Varies | 100/day | 5000/month |
| Attachments | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| HTML Emails | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| DKIM Auto | ✅ | ✅ | ✅ | Optional | ✅ | ✅ |
| Custom Headers | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Priority Headers | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Security | Excellent | Excellent | Good | Good | Excellent | Excellent |
| Deliverability | Excellent | Excellent | Good | Varies | Excellent | Excellent |
| Best For | Personal/Small | Enterprise | Personal | Custom | Marketing | Bulk/Dev |
# Base URL (required for OAuth callbacks in production)
URL=https://yourdomain.com
# Database (Strapi default)
DATABASE_CLIENT=postgres
DATABASE_HOST=127.0.0.1
DATABASE_PORT=5432
DATABASE_NAME=strapi
DATABASE_USERNAME=strapi
DATABASE_PASSWORD=password
# Optional - Custom encryption key
ENCRYPTION_KEY=your-32-byte-secret-key-hereUpdate redirect URIs in your OAuth apps:
Gmail:
https://yourdomain.com/magic-mail/oauth/gmail/callback
Microsoft:
https://yourdomain.com/magic-mail/oauth/microsoft/callback
Yahoo:
https://yourdomain.com/magic-mail/oauth/yahoo/callback
For Production Apps:
| Use Case | Recommended Provider | Configuration |
|---|---|---|
| Transactional | SendGrid or Mailgun | High daily limit, dedicated IP |
| Marketing | SendGrid | List management, analytics |
| Notifications | SMTP or Gmail OAuth | Medium limits, reliable |
| Internal | Microsoft 365 | Company domain, OAuth |
| Development | Mailgun Sandbox | Free testing |
Create complex routing rules:
// Rule 1: VIP customers via premium account
{
name: "VIP Customer Emails",
matchType: "recipient",
matchValue: "@vip-customers.com",
accountName: "Premium SMTP",
fallbackAccountName: "Gmail OAuth",
priority: 10,
isActive: true
}
// Rule 2: Password resets via fast account
{
name: "Password Reset Emails",
matchType: "subject",
matchValue: "Password Reset",
accountName: "Fast Gmail",
priority: 9,
isActive: true
}
// Rule 3: Marketing via SendGrid
{
name: "Marketing Campaigns",
matchType: "emailType",
matchValue: "marketing",
accountName: "SendGrid Marketing",
priority: 8,
isActive: true
}For custom domains with SMTP:
1. Generate DKIM Keys:
openssl genrsa -out dkim_private.pem 1024
openssl rsa -in dkim_private.pem -pubout -out dkim_public.pem2. Add to DNS:
default._domainkey.yourdomain.com TXT "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA..."
3. Add to MagicMail SMTP Account:
// In account config (edit account → credentials):
{
host: "smtp.yourdomain.com",
port: 587,
user: "...",
pass: "...",
dkim: {
domainName: "yourdomain.com",
keySelector: "default",
privateKey: "-----BEGIN PRIVATE KEY-----\n..."
}
}Best practices for high-volume sending:
// Account Setup:
// Account A: Priority 10, Daily Limit: 500
// Account B: Priority 9, Daily Limit: 500
// Account C: Priority 8, Daily Limit: 500
// → Total capacity: 1500 emails/day
// MagicMail automatically:
// 1. Uses Account A until limit hit
// 2. Switches to Account B
// 3. Switches to Account C
// 4. All transparent to your code!We welcome contributions!
Found a bug? Open an issue
Have a feature idea? Start a discussion
Want to contribute code?
- Fork the repo
- Create a feature branch
- Make your changes
- Submit a pull request
MIT License
Copyright © 2025 Schero D.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
ADDITIONAL CONDITION: The license validation system (including but not limited to license-guard.js, license controller, and related API endpoints) must remain intact and functional. Removing, bypassing, or disabling the license validation system is strictly prohibited.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Built with:
- Strapi v5 - Headless CMS
- Nodemailer - SMTP client
- Heroicons - Beautiful icons
- styled-components - CSS-in-JS
Inspired by:
- Enterprise email requirements
- Multi-tenant application needs
- Developer experience first
Need help?
If MagicMail helps your project, please:
- ⭐ Star the repo on GitHub
- 📢 Share with your team
- 🐦 Tweet about it
Made with ❤️ for the Strapi Community
MagicMail - Because email management should be magical, not painful. ✨