Integrate Strapi with Mailgun to send transactional emails, newsletters, and notifications directly from your headless CMS using Mailgun's reliable email delivery infrastructure and analytics.

Mailgun is an API-first email delivery service built specifically for developers who need to send transactional emails programmatically. Unlike marketing-focused email platforms, Mailgun specializes in automated, triggered messages: password resets, order confirmations, user notifications, and system alerts.
Mailgun provides both RESTful HTTP API and SMTP integration options for sending emails. This architecture gives you direct control over email delivery without managing mail servers or dealing with deliverability complexities.
Beyond basic sending, Mailgun includes several powerful features:
These capabilities give you complete visibility into your email pipeline without building custom tracking infrastructure.
Integrating Mailgun with Strapi's headless CMS eliminates the need to build custom email infrastructure through the official @strapi/provider-email-mailgun plugin. This allows you to trigger emails from lifecycle hooks, custom controllers, or scheduled jobs without building custom SMTP servers or queue systems from scratch.
Developer workflow advantages start with installation simplicity. Install the provider package, add configuration to config/plugins.js with your API credentials, and immediately access Mailgun's complete API through Strapi's standardized email interface. No custom SDK integration or HTTP client configuration is required. The plugin uses mailgun.js, the official actively maintained SDK.
Mailgun recommends its API over SMTP for transactional email. RESTful HTTP requests provide better error handling and built-in analytics than SMTP. Access batch sending, scheduled delivery (up to 3 days), and dynamic template support without custom queue management.
Real-world use cases span multiple scenarios:
Mailgun's template system supports Handlebars syntax for dynamic content, enabling personalized emails with conditional logic and data iteration.
Track performance metrics (open rates, click-through rates, bounce rates), geographic data, and detailed event logs with timestamps. Webhook integration streams delivery events in real-time, allowing you to build custom monitoring dashboards, trigger application logic based on engagement, and integrate email metrics into existing analytics infrastructure.
Scalability and reliability come standard. Mailgun operates with a 99.99% uptime guarantee through cloud-based infrastructure that automatically scales to handle volume increases without requiring configuration changes. Automated IP warmup gradually builds sender reputation for new dedicated IPs, while Mailgun's domain authentication and IP pools help manage deliverability.
Mailgun's compliance certifications reduce integration complexity for regulated industries.
This integration process takes approximately 30-45 minutes after DNS propagation completes. Each step builds on the previous one, ensuring proper authentication, domain verification, and email delivery functionality before moving to advanced features like templates and webhooks. Complete these steps sequentially: verify prerequisites, configure DNS records, install the provider plugin, and implement email logic.
Before starting integration, you need a working Strapi project and a Mailgun account with verified credentials. Your Strapi installation should be running locally or deployed to your preferred hosting environment; the integration works identically in both contexts.
Sign up for Mailgun at https://signup.mailgun.com/new/signup. The free tier provides 100 emails per day, sufficient for development and testing. After account activation, add an authorized recipient email through the Mailgun Dashboard and verify it through the confirmation email. This authorization is required for sandbox testing before domain verification completes. Test emails are restricted to authorized recipients only until your domain is verified.
Access your API key in the Mailgun Control Panel at Profile Menu → API Security. Critical: The full API key secret is displayed only once upon creation, so you must copy it and store it securely. If the secret is lost, you must generate or reset a new key, but you can always manage (view, disable, or regenerate) your API keys in the Control Panel. The integration requires an Account API Key (not a Domain Sending Key).
Domain verification proves domain ownership and enables production sending. Navigate to Sending → Domains in the Mailgun Control Panel and click "Add New Domain." Use a subdomain like mail.yourdomain.com rather than your root domain for better deliverability and domain isolation.
Configure four DNS records at your DNS provider: TXT for SPF (v=spf1 include:mailgun.org ~all), TXT for DKIM (unique RSA key), two MX records to mxa.mailgun.org and mxb.mailgun.org (priority 10), and CNAME for tracking. Important: One SPF record permitted per domain.
Most teams learn this the hard way when their second SPF record gets ignored and emails bounce. If an SPF record already exists, add include:mailgun.org to the existing record instead of creating a second one.
DNS propagation can take up to 24–48 hours globally, but often occurs faster. After allowing time for propagation and confirming your DNS changes are visible, click "Check DNS Records Now" in the Mailgun dashboard to verify. Until then, sandbox mode limits sending to authorized recipients only.
Start by installing the provider @strapi/provider-email-mailgun to integrate with Strapi's email system using your preferred package manager:
# Using npm
npm install @strapi/provider-email-mailgun --save
# Using yarn
yarn add @strapi/provider-email-mailgunBreaking change for Strapi v5: If you're migrating from Strapi v4, Strapi v5 requires using the updated key and url configuration variables instead of the legacy apiKey and host parameters. Update your configuration to use these new parameter names for the plugin to function properly.
After installation, create or update config/plugins.js (or plugins.ts for TypeScript). The plugin requires three provider options: API key (key), verified domain (domain), and API endpoint URL (url) for your region. Use environment variables via the env() helper: env('MAILGUN_API_KEY'), env('MAILGUN_DOMAIN'), and env('MAILGUN_URL', 'https://api.mailgun.net').
Configure the Mailgun provider in config/plugins.js using Strapi's environment variable helper for secure credential management:
module.exports = ({ env }) => ({
email: {
config: {
provider: 'mailgun',
providerOptions: {
key: env('MAILGUN_API_KEY'),
domain: env('MAILGUN_DOMAIN'),
url: env('MAILGUN_URL', 'https://api.mailgun.net'),
},
settings: {
defaultFrom: 'noreply@yourdomain.com',
defaultReplyTo: 'support@yourdomain.com',
},
},
},
});Use your Account API Key for key and verified domain for domain. European accounts use https://api.eu.mailgun.net for url.
Configure default sender addresses in the settings object. The defaultFrom address should be from your verified Mailgun domain for production (in sandbox mode, it must be an authorized recipient). The defaultReplyTo address is optional.
Create a .env file in your project root for environment variables:
MAILGUN_API_KEY=your-mailgun-api-key
MAILGUN_DOMAIN=mail.yourdomain.com
MAILGUN_URL=https://api.mailgun.net # or https://api.eu.mailgun.net for EUTest by sending an email through Strapi and checking both your inbox and Mailgun dashboard Logs to confirm successful delivery.
Mailgun templates use Handlebars syntax for variable substitution, conditional logic, and iteration. Create templates programmatically through the Template API or visually using Mailgun's Template Builder.
Templates support {{variableName}} variables, {{#if}} conditionals, and {{#each}} loops in Handlebars syntax. Here's a welcome email template:
<!DOCTYPE html>
<html>
<head>
<title>Welcome to {{appName}}</title>
</head>
<body>
<h1>Welcome, {{firstName}}!</h1>
{{#if needsVerification}}
<a href="{{verificationLink}}" style="background: #007bff; color: white; padding: 10px 20px;">
Verify Your Email
</a>
{{/if}}
</body>
</html>Send with variables:
await mg.messages.create(process.env.MAILGUN_DOMAIN, {
from: 'onboarding@yourdomain.com',
to: user.email,
template: 'welcome-email',
't:variables': JSON.stringify({
firstName: user.firstName,
appName: 'Your Application',
needsVerification: true,
verificationLink: `https://yourdomain.com/verify/${user.id}`
})
});Automate template sends via lifecycle hooks:
// ./src/api/user/content-types/user/lifecycles.js
module.exports = {
async afterCreate(event) {
const { result } = event;
if (result.emailPreferences?.onboardingEnabled) {
await strapi.service('api::email.email-service').sendWelcomeEmail(result);
}
}
};Configure a webhook route for Mailgun events without authentication:
// ./src/api/webhook/routes/webhook.js
module.exports = {
routes: [
{
method: 'POST',
path: '/webhooks/mailgun',
handler: 'mailgun-webhook.handleEvent',
config: {
auth: false,
},
},
],
};Verify webhook authenticity with HMAC SHA256 signature checking:
// ./src/api/webhook/controllers/mailgun-webhook.js
const crypto = require('crypto');
module.exports = {
async handleEvent(ctx) {
const { signature, 'event-data': eventData } = ctx.request.body;
const encodedToken = crypto
.createHmac('sha256', process.env.MAILGUN_WEBHOOK_SIGNING_KEY)
.update(signature.timestamp + signature.token)
.digest('hex');
if (encodedToken !== signature.signature) {
ctx.status = 403;
return ctx.body = { error: 'Invalid signature' };
}
await processMailgunEvent(eventData);
ctx.status = 200;
ctx.body = { received: true };
},
};Store events (delivered, opened, clicked, bounced, failed, unsubscribed, complained) in a Collection Type for analytics.
A production-ready onboarding email system often includes components such as template-based messaging, lifecycle event triggers, scheduled drip campaigns, and engagement tracking, but the exact technical stack varies by use case and is not standardized to five required elements.
The architecture creates a feedback loop where Strapi's lifecycle hooks trigger Mailgun API calls on user creation, Mailgun's scheduled delivery or your database-driven cron jobs control email timing, and webhook endpoints receive real-time events back into Strapi for analytics.
Mailgun's scheduling parameter (o:deliverytime) allows you to schedule emails up to your plan's maximum delivery window (typically 3 days, but up to 7 days on higher-tier plans) with no additional infrastructure required.
For longer or more complex campaigns—such as those requiring multi-step sequences, cancellation logic, or detailed engagement tracking—a database-driven approach with scheduled-email content types and background jobs may offer finer control. Teams often start with Mailgun's built-in scheduling and add custom scheduling when their requirements exceed native capabilities.
From a scalability perspective, this architecture handles growth through Mailgun's cloud infrastructure. As your user base grows, Mailgun automatically scales email delivery without configuration changes.
The bottleneck shifts to your database queries; indexing the scheduledFor and status fields in your scheduled-email Content Type becomes critical when processing thousands of pending sends every 5 minutes. The webhook endpoint needs similar attention: batch-insert email events rather than creating records one at a time, and index the messageId field for correlation with sent emails.
The user journey spans 7 days with three touchpoints. Immediately after signup, the welcome email fires from a lifecycle hook. On day 3, the tips email provides actionable guidance. On day 7, the check-in email assesses satisfaction.
Users control this flow through preference fields stored in their profile; toggling onboardingEnabled stops future sends without affecting delivered emails. Each email includes tracking pixels for opens and tracked links for clicks, feeding engagement data back through webhooks into your analytics.
Create a user Content Type schema at ./src/api/user/content-types/user/schema.json with fields for email preferences, onboarding status tracking, and engagement metrics. Include a JSON field for preference storage (onboardingEnabled, marketingEnabled, productUpdates), an enumeration for status (not_started, in_progress, completed), and datetime fields for lastEmailSent and emailsSent counter. This structure enables preference-based filtering and prevents duplicate sends during campaign execution.
Build three Handlebars templates in Mailgun: welcome-email, day-3-tips, and day-7-checkin. Each template accepts variables like {{firstName}}, {{dashboardUrl}}, and {{supportUrl}}. Enable tracking by including the o:tracking-opens and o:tracking-clicks parameters set to yes when sending template-based emails. Tag emails with the o:tag parameter set to onboarding.
Implement lifecycle hooks at ./src/api/user/content-types/user/lifecycles.js. The afterCreate hook checks emailPreferences.onboardingEnabled, sends welcome email via strapi.service('api::email.email-service').sendWelcomeEmail(result), schedules drip campaigns, and updates user records with onboardingStatus: 'in_progress'. Use Mailgun's scheduling parameter (o:deliverytime) for scheduling within 3 days or create a scheduled-email Content Type for longer campaigns.
Schedule day 3 and day 7 emails using either Mailgun's scheduling parameter (o:deliverytime) or a database-driven approach with Strapi cron jobs. Create a scheduled-email Collection Type storing user references, template names, scheduled timestamps, and send status. Configure a cron task in config/cron-tasks.js that queries pending emails every 5 minutes. The processor sends emails through your email service, updates status to sent or failed, and stores Mailgun message IDs for webhook correlation.
Create an email-event Collection Type storing event type, recipient, message ID, timestamp, and raw webhook payload. Configure webhook endpoints in Mailgun for delivered, opened, clicked, bounced, and failed events pointing to your custom Strapi webhook route at /api/webhooks/mailgun. Implement signature verification using HMAC SHA256 with Mailgun's webhook signing key. Process events to update user records: track lastEngagement on opens, log click URLs for behavior analysis, and flag delivery issues on bounces.
If you have any questions about Strapi 5 or just would like to stop by and say hi, you can join us at Strapi's Discord Open Office Hours, Monday through Friday, from 12:30 pm to 1:30 pm CST: Strapi Discord Open Office Hours.
For more details, visit the Strapi documentation and Mailgun documentation.
Verify you're using a Mailgun API Key (Account or Domain Sending Key) from Settings → API Security. Ensure your domain shows 'Verified' status after DNS propagation (24-48 hours). Sandbox mode requires authorized recipients.
Use the Mailgun API through the official provider plugin. The API offers better performance, error handling, template support, scheduled delivery, webhook tracking, and analytics than SMTP.
DNS records propagate in 24-48 hours globally. Verify records are published using command-line tools like dig or nslookup before clicking 'Check DNS Records Now' in the Mailgun dashboard. Until verification completes, you can only send to authorized recipients in sandbox mode.
Yes, use separate domains per environment: dev.yourdomain.com for development, mail.yourdomain.com for production. Configure environment-specific API keys and domains through .env variables referenced in config/plugins.js using env() helper. This prevents development emails from affecting production sender reputation.
Check Mailgun dashboard Logs for delivery attempts, bounce reasons, and failure codes. Implement webhook endpoints to capture real-time events. Common issues: unverified domains, invalid recipients, spam filters, or rate limits. Enable tracking in Mailgun settings to monitor engagement.