Skip to content

Magic-Mail โ€‹

Professional-grade multi-account email management with smart routing, OAuth 2.0 support, and complete security compliance

NPM VersionLicenseStrapi v5


๐Ÿ“– Quick Navigation โ€‹


Overview โ€‹

Stop fighting with .env files and email configuration! MagicMail brings enterprise email management to Strapi v5 with a beautiful admin interface, multiple provider support, and intelligent routing.

Key Features โ€‹

  • โœ… 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

Screenshots โ€‹

Email Accounts DashboardManage unlimited email accounts with live stats and real-time monitoring

Add Email AccountChoose from 6 different email providers with OAuth 2.0 support

Email DesignerDrag-and-drop email editor with real-time preview


Quick Start โ€‹

Installation โ€‹

bash
npm install strapi-plugin-magic-mail
# or
yarn add strapi-plugin-magic-mail

Enable Plugin โ€‹

Create or update config/plugins.ts:

typescript
export default () => ({
  'magic-mail': {
    enabled: true,
  },
});

Build & Start โ€‹

bash
npm run build
npm run develop

Add Your First Email Account โ€‹

  1. Navigate to Admin Panel โ†’ MagicMail โ†’ Email Accounts
  2. Click "Add Account"
  3. Choose your provider (Gmail OAuth, SMTP, etc.)
  4. Fill in credentials
  5. Click "Test" to verify
  6. Done! ๐ŸŽ‰

Supported Email Providers โ€‹

ProviderTypeAuthenticationFeatures
GmailOAuth 2.0Google OAuthGmail API, Attachments, Auto DKIM
Microsoft 365OAuth 2.0Azure ADGraph API, Attachments, Tenant Support
Yahoo MailOAuth 2.0Yahoo OAuthSMTP OAuth2, Attachments
SMTPCredentialsUsername/PasswordUniversal, DKIM Optional, Custom Servers
SendGridAPI KeySendGrid APITransactional, Marketing, Templates
MailgunAPI KeyMailgun APIBulk Sending, Analytics

Simple Email Sending โ€‹

MagicMail automatically intercepts Strapi's email service - no code changes needed!

javascript
// 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 statistics

Method 2: Direct MagicMail API โ€‹

javascript
// 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',
});

Sending with Attachments โ€‹

javascript
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',
    },
  ],
});

๐ŸŽฏ Use Cases โ€‹

Multi-Tenant SaaS โ€‹

javascript
// Each tenant gets their own email account
// Route by custom field
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
});

High-Volume Email Sending โ€‹

javascript
// 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!

Marketing Campaigns โ€‹

javascript
// Route marketing emails via SendGrid
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

Configuration โ€‹

Database Configuration โ€‹

Magic-Mail stores all email accounts securely in your Strapi database. No .env files needed!

Add to config/plugins.ts:

typescript
export default () => ({
  'magic-mail': {
    enabled: true,
    config: {
      // Optional: Custom encryption key (recommended for production)
      encryptionKey: process.env.MAGIC_MAIL_ENCRYPTION_KEY,
      
      // Optional: Enable detailed logging
      debug: process.env.NODE_ENV === 'development',
      
      // Optional: Custom rate limit settings
      rateLimit: {
        enabled: true,
        window: 3600, // seconds
        maxRequests: 100,
      },
    },
  },
});

Environment Variables (Optional) โ€‹

bash
# Encryption key for stored credentials
MAGIC_MAIL_ENCRYPTION_KEY=your-32-character-hex-key

# Enable debug mode
DEBUG=magic-mail:*

# Custom Redis connection for rate limiting (optional)
REDIS_URL=redis://localhost:6379

Generating Encryption Key โ€‹

bash
# Generate a secure encryption key
node -e "console.log(require('crypto').randomBytes(16).toString('hex'))"

๐ŸŽฏ Smart Routing Rules โ€‹

How Routing Rules Work โ€‹

Route emails automatically based on conditions:

javascript
// In Magic-Mail Admin Panel:
// 1. Go to Settings โ†’ Routing Rules
// 2. Create rule:
//    - Name: "Marketing Emails"
//    - Condition: type === "marketing"
//    - Account: SendGrid Marketing
//    - Priority: 10

Routing Rule Examples โ€‹

Example 1: Route by Email Type

Rule Name: Transactional Emails
Condition: type === "transactional"
Account: Gmail (high reliability)
Priority: 100

Example 2: Route by Recipient Domain

Rule Name: Enterprise Customers
Condition: to.endsWith("@enterprise.com")
Account: Microsoft 365 (enterprise support)
Priority: 90

Example 3: Route by Sender

Rule Name: Newsletter Emails
Condition: from.includes("newsletter")
Account: SendGrid (marketing features)
Priority: 80

Example 4: Failover Chain

Rule Name: High Volume
Condition: priority === "high"
Account: SendGrid (primary)
Fallback: Mailgun (secondary)
Priority: 95

Available Routing Conditions โ€‹

  • type - Email type (transactional, marketing, notification, system)
  • to - Recipient email address
  • from - Sender email address
  • subject - Email subject
  • priority - Email priority (high, normal, low)
  • customField - Custom metadata fields

Advanced Features โ€‹

Rate Limiting โ€‹

Each email account has configurable rate limits:

Gmail Account:
- Per day: 500 emails
- Per hour: 50 emails
- Per minute: 5 emails

SendGrid Account:
- Per day: 10,000 emails
- Per hour: 1,000 emails
- Per minute: 100 emails

MagicMail automatically:

  • Tracks sent emails in real-time
  • Switches to failover account when limit approached
  • Logs rate limit events
  • Sends notifications

Automatic Failover โ€‹

When an account hits rate limits:

SendGrid Primary (limit reached)
    โ†“
Mailgun Fallback (takes over)
    โ†“
SMTP Backup (last resort)

No emails lost! All queued emails retry automatically.

Email Logging & Analytics โ€‹

All emails are logged with:

  • Timestamp
  • Recipient address
  • Account used
  • Delivery status
  • Response time
  • Error messages (if any)

Access logs:

  1. Admin Panel โ†’ Magic-Mail โ†’ Email Logs
  2. Filter by date, account, status
  3. See delivery statistics

Troubleshooting โ€‹

Common Issues & Solutions โ€‹

Issue 1: "OAuth Token Expired"

Error: Google OAuth token expired
Solution: 
1. Go to Email Accounts
2. Click the account
3. Click "Re-authorize"
4. Follow Google OAuth flow

Issue 2: "Emails Not Sending"

Diagnosis steps:
1. Check Admin Panel โ†’ Email Logs
2. Look for error messages
3. Verify account credentials
4. Test account: click "Test" button
5. Check rate limits haven't been exceeded

Issue 3: "SMTP Connection Refused"

Solution:
1. Verify SMTP host & port (Gmail: smtp.gmail.com:587)
2. Enable "Less secure app access" (Gmail)
3. Check firewall allows outgoing port 587/25
4. Use TLS (not SSL) for most providers

Issue 4: "Magic-Mail Not Intercepting Emails"

Ensure:
1. Plugin enabled in config/plugins.ts
2. npm run build && npm run develop ran
3. At least one email account configured
4. Email account has "Active" status
5. Admin sidebar shows "Magic-Mail"

Issue 5: "403 Forbidden - SendGrid"

Solution:
1. Verify API key is correct (copy from SendGrid dashboard)
2. Check API key has "Mail Send" permission
3. Confirm API key is not revoked
4. Try creating new API key

Issue 6: "Attachments Not Working"

Not all providers support attachments equally:
โœ… Works: Gmail, Microsoft 365, Yahoo, SMTP
โš ๏ธ Limited: SendGrid (encoded only)
โŒ Not supported: Mailgun (API limitation)

Solution: Use email provider with full attachment support

Enable Debug Mode โ€‹

bash
# Terminal
DEBUG=magic-mail:* npm run develop

# Logs:
# - All routing decisions
# - Account selection logic
# - Rate limit tracking
# - Email send attempts

Check Logs Location โ€‹

bash
# Docker
docker logs strapi-container | grep magic-mail

# Standard
# Check: /var/log/strapi/magic-mail.log
# or: your-strapi-dir/logs/magic-mail.log

Complete API Reference โ€‹

Send Email Endpoint โ€‹

Direct API Usage (Strapi Plugin Service):

javascript
// Method: Strapi Native (Recommended)
const emailService = strapi.plugin('email').service('email');

await emailService.send({
  to: 'user@example.com',
  cc: 'manager@example.com',
  bcc: 'archive@example.com',
  subject: 'Order Confirmation',
  text: 'Plain text fallback',
  html: '<h1>Thanks for your order!</h1>',
  replyTo: 'support@company.com',
});

Method 2: Direct Magic-Mail Service (For advanced routing)

javascript
const magicMailService = strapi.plugin('magic-mail').service('email-router');

await magicMailService.send({
  // Recipients
  to: 'user@example.com',
  cc: ['manager1@example.com', 'manager2@example.com'],
  bcc: ['archive@company.com'],
  
  // Content
  subject: 'Your Order #12345',
  text: 'Plain text version',
  html: '<h1>HTML version</h1>',
  replyTo: 'support@company.com',
  
  // Routing
  accountName: 'SendGrid Marketing', // Specific account
  type: 'marketing', // For routing rules
  priority: 'high', // high | normal | low
  
  // Attachments
  attachments: [
    {
      filename: 'invoice.pdf',
      path: './uploads/invoice-12345.pdf',
    },
    {
      filename: 'terms.txt',
      content: 'File content as string',
    },
  ],
  
  // Email ID for tracking
  messageId: 'order-12345-1234567890',
  
  // Custom metadata
  metadata: {
    orderId: '12345',
    customerId: 'cust-999',
    campaignId: 'summer-2025',
  },
});

Send with Email Template โ€‹

javascript
await strapi.plugin('magic-mail').service('email-router').send({
  to: 'user@example.com',
  
  // Use saved template
  template: {
    id: 'welcome-email', // Template ID from Magic-Mail
    data: {
      firstName: 'John',
      lastName: 'Doe',
      companyName: 'Acme Corp',
      activationLink: 'https://app.example.com/activate?token=abc123',
    },
  },
});

Query Email Logs โ€‹

javascript
// Get all sent emails
const logs = await strapi.db.query('magic-mail::email-log').findMany({
  limit: 100,
  offset: 0,
  orderBy: { createdAt: 'desc' },
});

// Get by status
const failedEmails = await strapi.db.query('magic-mail::email-log').findMany({
  where: { status: 'failed' },
  limit: 50,
});

// Get by account
const gmailEmails = await strapi.db.query('magic-mail::email-log').findMany({
  where: { accountName: 'Gmail' },
  limit: 100,
});

Webhook Events โ€‹

Email events that trigger webhooks:

javascript
// Event: Email Sent Successfully
{
  event: 'email.sent',
  messageId: 'msg-12345',
  to: 'user@example.com',
  account: 'SendGrid',
  sentAt: '2025-01-15T10:30:00Z',
}

// Event: Email Failed
{
  event: 'email.failed',
  messageId: 'msg-12345',
  to: 'user@example.com',
  account: 'Gmail',
  error: 'Authentication failed',
  failedAt: '2025-01-15T10:30:00Z',
}

// Event: Rate Limit Hit
{
  event: 'account.rateLimitHit',
  account: 'SendGrid',
  limit: 10000,
  period: 'daily',
  hitAt: '2025-01-15T10:30:00Z',
}

// Event: Account Deactivated
{
  event: 'account.deactivated',
  account: 'Gmail',
  reason: 'OAuth token expired',
  deactivatedAt: '2025-01-15T10:30:00Z',
}

Best Practices โ€‹

1. Email Routing Strategy โ€‹

javascript
// โœ… Good: Use routing rules for different email types
// Transactional โ†’ Gmail (high reliability)
// Marketing โ†’ SendGrid (features)
// Notifications โ†’ SMTP Backup (lightweight)

// โŒ Bad: Send everything through one account
// - Risks hitting rate limits
// - No failover
// - No load balancing

2. Error Handling โ€‹

javascript
// โœ… Good: Wrap in try-catch
try {
  await strapi.plugin('email').service('email').send({
    to: user.email,
    subject: 'Welcome!',
    html: template,
  });
} catch (error) {
  console.error('Email failed:', error.message);
  // Log to external service
  // Retry later
  // Notify admin
}

// โŒ Bad: Fire and forget
strapi.plugin('email').service('email').send({...});

3. Rate Limiting Strategy โ€‹

javascript
// โœ… Good: Multiple accounts for high volume
// Account 1: 500/day
// Account 2: 500/day
// Account 3: 500/day
// Total capacity: 1500/day

// โŒ Bad: Single account for high volume
// Hits limit quickly
// No failover

4. Template Management โ€‹

javascript
// โœ… Good: Store templates in Magic-Mail
// - Easy to update in Admin Panel
// - Version history
// - Re-use across projects

// โŒ Bad: Template in code
// - Hard to update
// - Deployment needed for changes
// - No version control

5. OAuth Token Refresh โ€‹

javascript
// โœ… Good: Setup automatic re-authorization
// Check: Admin Panel โ†’ Settings โ†’ OAuth
// Enable: Auto-refresh tokens

// โŒ Bad: Let tokens expire
// - Emails stop sending
// - Manual re-authorization needed
// - Service interruption

6. Monitoring โ€‹

javascript
// โœ… Good: Monitor these metrics
// - Daily email count
// - Failed email count
// - Rate limit usage
// - Response times
// - OAuth token expiry

// โŒ Bad: No monitoring
// - Discover issues when users complain
// - No advance warning

๐ŸŽ“ Example: Complete Setup Flow โ€‹

Goal: Send transactional emails from multiple providers with automatic failover

Step 1: Install & Enable

bash
npm install strapi-plugin-magic-mail
npm run build && npm run develop

Step 2: Add Email Accounts

  • Gmail Account (OAuth)
  • SendGrid Account (API Key)
  • SMTP Fallback

Step 3: Create Routing Rules

  • Rule 1: type="transactional" โ†’ Gmail
  • Rule 2: type="transactional" + priority="high" โ†’ SendGrid
  • Fallback: SMTP

Step 4: Send Emails

javascript
await strapi.plugin('email').service('email').send({
  to: user.email,
  subject: 'Welcome!',
  html: '<h1>Thanks!</h1>',
  type: 'transactional',
});
// Automatically routes to Gmail or SendGrid based on rules

Step 5: Monitor

  • Admin Panel โ†’ Magic-Mail โ†’ Email Logs
  • Check success rate
  • Monitor rate limits

Design beautiful emails visually with the integrated email designer!

FeatureFREEPREMIUMADVANCED
Visual Designerโœ… Basicโœ… + libraryโœ… Pro components
Templates25100500
Drag & Dropโœ…โœ…โœ…
Mustache Variablesโœ…โœ…โœ…
Version HistoryโŒโœ…โœ…
AnalyticsโŒBasicAdvanced
A/B TestingโŒโŒโœ…

Creating Templates โ€‹

javascript
// 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',
    },
    orderNumber: '12345',
    orderTotal: '$199.99',
  },
});

Security Features โ€‹

Credential Encryption โ€‹

All sensitive data is encrypted using AES-256-GCM before storage:

Data TypeEncryptionStorage
SMTP PasswordsAES-256-GCMEncrypted in database
OAuth Access TokensAES-256-GCMEncrypted in database
OAuth Refresh TokensAES-256-GCMEncrypted in database
API Keys (SendGrid, Mailgun)AES-256-GCMEncrypted in database

Setup Encryption Key:

bash
# Generate a secure 32-character hex key
openssl rand -hex 32

# Add to .env file
MAGIC_MAIL_ENCRYPTION_KEY=your-64-character-hex-key

Without encryption key: Credentials are still protected using Strapi's built-in encryption, but a custom key is recommended for production.

Transport Security โ€‹

  • โœ… TLS 1.2+ enforced (SMTP connections)
  • โœ… Certificate verification enabled by default
  • โœ… HTTPS only for API providers (SendGrid, Mailgun, Brevo)
  • โœ… Secure OAuth flows with state verification

Email Authentication โ€‹

  • โœ… DKIM signing (automatic for OAuth, optional for SMTP)
  • โœ… SPF validation support
  • โœ… DMARC compliance

Compliance โ€‹

  • โœ… GDPR - List-Unsubscribe header included
  • โœ… CAN-SPAM - One-click unsubscribe support
  • โœ… RFC 5322 - Proper email format validation

Pricing โ€‹

FeatureFreePremiumAdvanced
Email Accounts3UnlimitedUnlimited
All 6 Providersโœ…โœ…โœ…
Smart Routingโœ…โœ…โœ…
Templates25100500
Version HistoryโŒโœ…โœ…
AnalyticsโŒBasicAdvanced
Priority SupportโŒโŒโœ…

View Full Pricing โ†’


Complete Documentation Index โ€‹

This documentation covers everything you need to get started with Magic-Mail:

  1. Overview - Features and capabilities
  2. Quick Start - Installation and basic setup (5 minutes)
  3. Email Providers - All 6 supported providers
  4. Email Sending - 3 methods with examples
  5. Use Cases - Real-world scenarios
  6. Email Designer - Template system features
  7. Configuration - Advanced settings
  8. Smart Routing - Automatic email routing rules
  9. Advanced Features - Rate limiting, failover, logging
  10. Troubleshooting - Common issues and solutions
  11. API Reference - Complete developer reference
  12. Best Practices - Production-ready strategies
  13. Security - Encryption and compliance
  14. Pricing - All tiers and features

Next Steps:


Get Magic-Mail โ€‹

Ready to supercharge your email management? Magic-Mail is completely free to get started!

Get Magic-Mail Free โ†’

No credit card required ยท Free tier forever ยท 30-day money-back guarantee


Perfect Together:

  • ๐Ÿ”— Magic-Link - Passwordless authentication for sending magic link emails
  • ๐Ÿ” Magic-Sessionmanager - Track user sessions and send security alerts
  • ๐Ÿ”– Magic-Mark - Bookmark email templates and queries

๐Ÿ’ฌ Support & Resources โ€‹


Made with โค๏ธ by Schero D.

MagicMail - Because email management should be magical, not painful. โœจ