How to start receiving inbound email


Add Receiving MX Records

Your domain needs Mailgun MX records to handle inbound messages. Open up your DNS provider and add these. MX Information

Type Value Purpose
MX Receiving (Optional)
MX Receiving (Optional)


Do not configure Receiving MX DNS records if you already have another provider handling inbound mail delivery for your domain (e.g. Gmail). Instead we recommend using a subdomain on Mailgun (e.g.

Inbound Routes and Parsing

You can define a list of routes to handle incoming emails and prioritize the sequence of their execution.

  • Each route consists of a filter expression and an action.
  • When a message is received, Mailgun evaluates the filter expression against it.
  • If the expression is true, the action is executed.

Regular expressions can be used to match against message recipients or arbitrary headers such as subject.

Examples of filter expressions for routes

Expression Description
match_recipient(””) Returns true if the incoming message is going to
match_recipient(“.*”) Returns true if the incoming message is going to any user at
match_header(“subject”, “hello”) Returns true if the subject of the message contains word ‘hello’.
catch_all() Returns true if no other route matched, to implement catch-all behaviour.

Supported actions for routes

Action Description
forward(”http://myapp/post”) Parses the message and forwards it to a given URL.
forward(””) Forwards the message to a given email address.
store(notify=”http://myapp/post”) Stores the message temporarily to be retrieved later.
stop() Stops and doesn’t look at any other routes.

Routes can be defined and tested using the Mailgun API (in addition, to using the Control Panel).

curl -s --user 'api:YOUR_API_KEY' \ \
   -F priority=0 \
   -F description='Sample route' \
   -F expression='match_recipient(".*@YOUR_DOMAIN_NAME")' \
   -F action='forward("")' \
   -F action='stop()'
import com.mailgun.api.v3.MailgunRoutesApi;
import com.mailgun.model.routes.RoutesRequest;
import com.mailgun.model.routes.RoutesResponse;

// ...

public RoutesResponse createRoute() {
    MailgunRoutesApi mailgunRoutesApi = MailgunClient.config(API_KEY)

    RoutesRequest routesRequest = RoutesRequest.builder()
        .description("sample route")

    return mailgunRoutesApi.createRoute(routesRequest);
# Include the Autoloader (see "Libraries" for install instructions)
require 'vendor/autoload.php';
use Mailgun\Mailgun;

# Instantiate the client.
$mgClient = Mailgun::create('PRIVATE_API_KEY', 'https://API_HOSTNAME');

# Define your expression, actions, and description
$expression   = 'match_recipient(".*")';
$actions      = array('forward("")', 'stop()');
$description  = 'Catch All and Forward';

# Issue the call to the client.
$result = $mgClient->routes()->create($expression, $actions, $description);
def create_route():
        auth=("api", "YOUR_API_KEY"),
        data={"priority": 0,
              "description": "Sample route",
              "expression": "match_recipient('.*@YOUR_DOMAIN_NAME')",
              "action": ["forward('')", "stop()"]})
def create_route
  data = {}
  data[:priority] = 0
  data[:description] = "Sample route"
  data[:expression] = "match_recipient('.*@YOUR_DOMAIN_NAME')"
  data[:action] = []
  data[:action] << "forward('')"
  data[:action] << "stop()" "https://api:YOUR_API_KEY"\
  "", data
using System;
using System.IO;
using RestSharp;
using RestSharp.Authenticators;

public class CreateRouteChunk

    public static void Main (string[] args)
        Console.WriteLine (CreateRoute ().Content.ToString ());

    public static IRestResponse CreateRoute ()
        RestClient client = new RestClient ();
        client.BaseUrl = new Uri ("");
        client.Authenticator =
            new HttpBasicAuthenticator ("api",
        RestRequest request = new RestRequest ();
        request.Resource = "routes";
        request.AddParameter ("priority", 0);
        request.AddParameter ("description", "Sample route");
        request.AddParameter ("expression", "match_recipient('.*@YOUR_DOMAIN_NAME')");
        request.AddParameter ("action",
        request.AddParameter ("action", "stop()");
        request.Method = Method.POST;
        return client.Execute (request);

import (

func CreateRoute(domain, apiKey string) (mailgun.Route, error) {
    mg := mailgun.NewMailgun(domain, apiKey)

    ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
    defer cancel()

    return mg.CreateRoute(ctx, mailgun.Route{
        Priority:    1,
        Description: "Sample Route",
        Expression:  "match_recipient(\".*@YOUR_DOMAIN_NAME\")",
        Actions: []string{
import formData from 'form-data';
import Mailgun from 'mailgun.js';

const mailgun = new Mailgun(formData);

const client = mailgun.client({ username: 'api', key: 'YOUR_API_KEY' || '' });
(async () => {
  try {
    const createdRoute = await client.routes.create({
      expression: 'match_recipient(".*@YOUR_DOMAIN_NAME")',
      action: ['forward("")', 'stop()'],
      description: 'Sample route'
    console.log('createdRoute', createdRoute);
  } catch (error) {

The example above defines a new route which will forward all messages coming to to and will stop evaluating any other routes.

Now let’s look at how to build HTTP handlers for incoming messages, i.e. what needs to be done on your end to handle a message that Mailgun forwards to your URL.

Consider this Django code:

# Handler for HTTP POST to for the route defined above
def on_incoming_message(request):
     if request.method == 'POST':
         sender    = request.POST.get('sender')
         recipient = request.POST.get('recipient')
         subject   = request.POST.get('subject', '')

         body_plain = request.POST.get('body-plain', '')
         body_without_quotes = request.POST.get('stripped-text', '')
         # note: other MIME headers are also posted here...

         # attachments:
         for key in request.FILES:
             file = request.FILES[key]
             # do something with the file

     # Returned text is ignored but HTTP status code matters:
     # Mailgun wants to see 2xx, otherwise it will make another attempt in 5 minutes
     return HttpResponse('OK')

Mailgun routes are very powerful. For example, you can use regular expression captures and refer to captured values in your destination.

To learn more about Routes, check out the Routes section of the User Manual.