These integration guides are not official documentation and the Strapi Support Team will not provide assistance with them.
What Is Mailgun?
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:
- Email validation that performs mailbox verification, detects disposable addresses, corrects common typos (e.g., "gmial.com"), and provides risk scoring
- Analytics dashboard with customizable metrics and configurable filters for tracking delivery status
- Event logging that monitors open rates, click-through rates, and bounce patterns
- Webhook streaming that delivers real-time delivery events via HMAC SHA256-signed requests
These capabilities give you complete visibility into your email pipeline without building custom tracking infrastructure.
Why Integrate Mailgun with Strapi
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:
- Authentication flows for password resets, email verification, and two-factor codes
- User notifications including order confirmations and status updates
- Onboarding sequences with welcome emails and product tours
- System alerts for security notifications and suspicious activity warnings
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.
How to Integrate Mailgun with Strapi
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.
Prerequisites
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).
Creating and Verifying Your Mailgun Domain
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.
Installing the Strapi Mailgun Provider
Start by installing the provider @strapi/provider-email-mailgun to integrate with Strapi's email system using your preferred package manager:
1# Using npm
2npm install @strapi/provider-email-mailgun --save
3
4# Using yarn
5yarn 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').
Configuring Email Plugin Settings
Configure the Mailgun provider in config/plugins.js using Strapi's environment variable helper for secure credential management:
1module.exports = ({ env }) => ({
2 email: {
3 config: {
4 provider: 'mailgun',
5 providerOptions: {
6 key: env('MAILGUN_API_KEY'),
7 domain: env('MAILGUN_DOMAIN'),
8 url: env('MAILGUN_URL', 'https://api.mailgun.net'),
9 },
10 settings: {
11 defaultFrom: 'noreply@yourdomain.com',
12 defaultReplyTo: 'support@yourdomain.com',
13 },
14 },
15 },
16});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:
1MAILGUN_API_KEY=your-mailgun-api-key
2MAILGUN_DOMAIN=mail.yourdomain.com
3MAILGUN_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.
Building Reusable Email Templates in Mailgun
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:
1<!DOCTYPE html>
2<html>
3<head>
4 <title>Welcome to {{appName}}</title>
5</head>
6<body>
7 <h1>Welcome, {{firstName}}!</h1>
8
9 {{#if needsVerification}}
10 <a href="{{verificationLink}}" style="background: #007bff; color: white; padding: 10px 20px;">
11 Verify Your Email
12 </a>
13 {{/if}}
14</body>
15</html>Send with variables:
1await mg.messages.create(process.env.MAILGUN_DOMAIN, {
2 from: 'onboarding@yourdomain.com',
3 to: user.email,
4 template: 'welcome-email',
5 't:variables': JSON.stringify({
6 firstName: user.firstName,
7 appName: 'Your Application',
8 needsVerification: true,
9 verificationLink: `https://yourdomain.com/verify/${user.id}`
10 })
11});Automate template sends via lifecycle hooks:
1// ./src/api/user/content-types/user/lifecycles.js
2module.exports = {
3 async afterCreate(event) {
4 const { result } = event;
5
6 if (result.emailPreferences?.onboardingEnabled) {
7 await strapi.service('api::email.email-service').sendWelcomeEmail(result);
8 }
9 }
10};Handling Webhooks for Delivery Tracking
Configure a webhook route for Mailgun events without authentication:
1// ./src/api/webhook/routes/webhook.js
2module.exports = {
3 routes: [
4 {
5 method: 'POST',
6 path: '/webhooks/mailgun',
7 handler: 'mailgun-webhook.handleEvent',
8 config: {
9 auth: false,
10 },
11 },
12 ],
13};Verify webhook authenticity with HMAC SHA256 signature checking:
1// ./src/api/webhook/controllers/mailgun-webhook.js
2const crypto = require('crypto');
3
4module.exports = {
5 async handleEvent(ctx) {
6 const { signature, 'event-data': eventData } = ctx.request.body;
7
8 const encodedToken = crypto
9 .createHmac('sha256', process.env.MAILGUN_WEBHOOK_SIGNING_KEY)
10 .update(signature.timestamp + signature.token)
11 .digest('hex');
12
13 if (encodedToken !== signature.signature) {
14 ctx.status = 403;
15 return ctx.body = { error: 'Invalid signature' };
16 }
17
18 await processMailgunEvent(eventData);
19
20 ctx.status = 200;
21 ctx.body = { received: true };
22 },
23};Store events (delivered, opened, clicked, bounced, failed, unsubscribed, complained) in a Collection Type for analytics.
Project Example: Build a User Onboarding Email System with Mailgun and Strapi
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.
Step 1: Set Up User Content Type with Email Preferences
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.
Step 2: Create Onboarding Email Templates in Mailgun
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.
Step 3: Build Lifecycle Hooks for Automated Triggers
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.
Step 4: Implement Drip Campaign Logic
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.
Step 5: Track Engagement with Webhook Events
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.
Strapi Open Office Hours
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.