Routes

Mailgun Routes are a powerful way to handle the incoming traffic. See Routes section in the User Manual to learn more about how they work. This API allows you to work with routes programmatically.

Routes are comprised of the following arguments:

  • A filter (when to do something).
  • A priority (in what order).
  • An action (what to do).

Filters

Route filters are expressions that determine when an action is triggered. You can create a filter based on the recipient of the incoming email, the headers in the incoming email or use a catch-all filter. Filters support regular expressions in the pattern to give you a lot of flexibility when creating them.

match_recipient(pattern)

Matches smtp recipient of the incoming message against the regular expression pattern. For example this will match all messages coming to any recipient at @bar.com:

match_recipient(".*@bar.com")

match_header(header, pattern)

Similar to match_recipient but instead of looking at a message recipient, it applies the pattern to an arbitrary MIME header of the message. For this will match any message with a word “support” in its subject:

match_header("subject", ".*support")

catch_all()

Matches if no preceeding routes matched. Usually you need to use it in a route with a lowest priority, to make sure it evaluates last.

Actions

If a route expression evaluates to true, Mailgun executes the corresponding action. Currently you can use the following three actions in your routes: forward(), store() and stop().

forward(destination)

Forwards the message to a specified destination, which can be another email address or a URL. A few examples:

forward("mailbox@myapp.com")
forward("http://myapp.com/messages")

store(notification endpoint)

Stores the message temporarily (for up to 3 days) on Mailgun’s servers so that you can retrieve them later. This is helpful for large messages that may cause time outs or if you just want to retrieve them later.

You can specify a URL and we will notify you when the email arrives along with a URL where you can use to retrieve the message:

store(notify="http://mydomain.com/callback")

You can see a full list of parameters we will post to your URL in the Routes section of the User Manual. You can also get the locations of messages through the Events API and then retrieve the message through the Messages API.

stop()

Simply stops the priority waterfall so the subsequent routes will not be evaluated. Without a stop() action executed, all lower priority Routes will also be evaluated.

GET /routes

Fetches the list of routes. Note that routes are defined globally, per account, not per domain as most of other API calls.

Parameter Description
limit Maximum number of records to return. (100 by default)
skip Number of records to skip. (0 by default)
GET /routes/<id>

Returns a single route object based on its ID. See examples below.

Parameter Description
routeId ID of the route
POST /routes

Creates a new route.

Parameter Description
priority Integer: smaller number indicates higher priority. Higher priority routes are handled first. Defaults to 0.
description An arbitrary string.
expression A filter expression like match_recipient('.*@gmail.com')
action Route action. This action is executed when the expression evaluates to True. Example: forward("alice@example.com") You can pass multiple action parameters.
PUT /routes/<id>

Updates a given route by ID. All parameters are optional: this API call only updates the specified fields leaving others unchanged.

Parameter Description
routeId ID of the route
priority Integer: smaller number indicates higher priority. Higher priority routes are handled first.
description An arbitrary string.
expression A filter expression like match_recipient('.*@gmail.com')
action Route action. This action is executed when the expression evaluates to True. Example: forward("alice@example.com") You can pass multiple action parameters.
DELETE /routes/<id>

Deletes a route based on the id.

Parameter Description
routeId ID of the route

Examples

Create a route of the highest priority with multiple actions:

curl -s --user 'api:YOUR_API_KEY' \
    https://api.mailgun.net/v3/routes \
    -F priority=0 \
    -F description='Sample route' \
    -F expression='match_recipient(".*@YOUR_DOMAIN_NAME")' \
    -F action='forward("http://myhost.com/messages/")' \
    -F action='stop()'
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;

import javax.ws.rs.core.Form;
import javax.ws.rs.core.MediaType;

import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;

public class MGSample {

    // ...

    public static ClientResponse CreateRoute() {

        Client client = ClientBuilder.newClient();
        client.register(HttpAuthenticationFeature.basic(
            "api",
            "YOUR_API_KEY"
        ));

        WebTarget mgRoot = client.target("https://api.mailgun.net/v3");

        Form reqData = new Form();
        reqData.param("priority", 0);
        reqData.param("description", "Sample route");
        reqData.param("expression", "match_recipient('.*@YOUR_DOMAIN_NAME')");
        reqData.param("action", "forward('http://myhost.com/messages/')");
        reqData.param("action", "stop()");

        return mgRoot
            .path("/routes")
            .request(MediaType.APPLICATION_FORM_URLENCODED)
            .buildPost(Entity.entity(reqData, MediaType.APPLICATION_FORM_URLENCODED))
            .invoke(ClientResponse.class);
    }
}
# Include the Autoloader (see "Libraries" for install instructions)
require 'vendor/autoload.php';
use Mailgun\Mailgun;

# Instantiate the client.
$mgClient = new Mailgun('YOUR_API_KEY');

# Issue the call to the client.
$result = $mgClient->post("routes", array(
    'priority'    => 0,
    'expression'  => 'match_recipient(".*@YOUR_DOMAIN_NAME")',
    'action'      => array('forward("http://host.com/messages")', 'stop()'),
    'description' => 'Sample route'
));
def create_route():
    return requests.post(
        "https://api.mailgun.net/v3/routes",
        auth=("api", "YOUR_API_KEY"),
        data={"priority": 0,
              "description": "Sample route",
              "expression": "match_recipient('.*@YOUR_DOMAIN_NAME')",
              "action": ["forward('http://myhost.com/messages/')", "stop()"]})
def create_route
  data = {}
  data[:priority] = 0
  data[:description] = "Sample route"
  data[:expression] = "match_recipient('.*@YOUR_DOMAIN_NAME')"
  data[:action] = []
  data[:action] << "forward('http://myhost.com/messages/')"
  data[:action] << "stop()"
  RestClient.post "https://api:YOUR_API_KEY"\
  "@api.mailgun.net/v3/routes", data
end
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 ("https://api.mailgun.net/v3");
        client.Authenticator =
            new HttpBasicAuthenticator ("api",
                                        "YOUR_API_KEY");
        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",
                              "forward('http://myhost.com/messages/')");
        request.AddParameter ("action", "stop()");
        request.Method = Method.POST;
        return client.Execute (request);
    }

}
func CreateRoute(domain, apiKey string) (mailgun.Route, error) {
  mg := mailgun.NewMailgun(domain, apiKey, "")
  return mg.CreateRoute(mailgun.Route{
    Priority:    1,
    Description: "Sample Route",
    Expression:  "match_recipient(\".*@YOUR_DOMAIN_NAME\")",
    Actions: []string{
      "forward(\"http://example.com/messages/\")",
      "stop()",
    },
  })
}

Sample response:

{
  "message": "Route has been created",
  "route": {
      "description": "Sample route",
      "created_at": "Wed, 15 Feb 2012 13:03:31 GMT",
      "actions": [
          "forward(\"http://myhost.com/messages/\")",
          "stop()"
      ],
      "priority": 0,
      "expression": "match_recipient(\".*@samples.mailgun.org\")",
      "id": "4f3bad2335335426750048c6"
  }
}

Listing routes:

curl -s --user 'api:YOUR_API_KEY' -G \
    https://api.mailgun.net/v3/routes \
    -d skip=1 \
    -d limit=1
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;

import javax.ws.rs.core.Form;
import javax.ws.rs.core.MediaType;

import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;

public class MGSample {

    // ...

    public static ClientResponse ParseAddresses() {

        Client client = ClientBuilder.newClient();
        client.register(HttpAuthenticationFeature.basic(
            "api",
            "YOUR_API_KEY"
        ));

        WebTarget mgRoot = client.target("https://api.mailgun.net/v3");

        return mgRoot
            .path("/routes")
            .queryParam("skip", 1)
            .queryParam("limit", 1)
            .request()
            .buildGet()
            .invoke(ClientResponse.class);
    }
}
# Include the Autoloader (see "Libraries" for install instructions)
require 'vendor/autoload.php';
use Mailgun\Mailgun;

# Instantiate the client.
$mgClient = new Mailgun('YOUR_API_KEY');

# Issue the call to the client.
$result = $mgClient->get("routes", array('skip' => 5, 'limit' => 10));
def get_routes():
    return requests.get(
        "https://api.mailgun.net/v3/routes",
        auth=("api", "YOUR_API_KEY"),
        params={"skip": 1,
                "limit": 1})
def get_routes
  RestClient.get "https://api:YOUR_API_KEY"\
  "@api.mailgun.net/v3/routes", :params => {
    :skip => 1,
    :limit => 1
  }
end
using System;
using System.IO;
using RestSharp;
using RestSharp.Authenticators;

public class GetRoutesChunk
{

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

    public static IRestResponse GetRoutes ()
    {
        RestClient client = new RestClient ();
        client.BaseUrl = new Uri ("https://api.mailgun.net/v3");
        client.Authenticator =
            new HttpBasicAuthenticator ("api",
                                        "YOUR_API_KEY");
        RestRequest request = new RestRequest ();
        request.Resource = "routes";
        request.AddParameter ("skip", 1);
        request.AddParameter ("limit", 1);
        return client.Execute (request);
    }

}
func GetRoutes(domain, apiKey string) (int, []mailgun.Route, error) {
  mg := mailgun.NewMailgun(domain, apiKey, "")
  return mg.GetRoutes(-1, -1)
}

Sample response:

{
  "total_count": 266,
  "items": [
      {
          "description": "Sample route",
          "created_at": "Wed, 15 Feb 2012 12:58:12 GMT",
          "actions": [
              "forward(\"http://myhost.com/messages/\")",
              "stop()"
          ],
          "priority": 0,
          "expression": "match_recipient(\".*@samples.mailgun.org\")",
          "id": "4f3babe4ba8a481c6400476a"
      }
  ]
}

Access the route by id:

curl -s --user 'api:YOUR_API_KEY' \
    https://api.mailgun.net/v3/routes/4f3bad2335335426750048c6
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;

import javax.ws.rs.core.Form;
import javax.ws.rs.core.MediaType;

import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;

public class MGSample {

    // ...

    public static ClientResponse GetRoute() {

        Client client = ClientBuilder.newClient();
        client.register(HttpAuthenticationFeature.basic(
            "api",
            "YOUR_API_KEY"
        ));

        WebTarget mgRoot = client.target("https://api.mailgun.net/v3");

        return mgRoot
            .path("/routes/{route_id}")
            .resolveTemplate("route_id", "YOUR_ROUTE_ID")
            .request()
            .buildGet()
            .invoke(ClientResponse.class);
    }
}
# Include the Autoloader (see "Libraries" for install instructions)
require 'vendor/autoload.php';
use Mailgun\Mailgun;

# Instantiate the client.
$mgClient = new Mailgun('YOUR_API_KEY');
$routeId = '4e97c1b2ba8a48567f007fb6';

# Issue the call to the client.
$result = $mgClient->get("routes/$routeId");
def get_route():
    return requests.get(
        "https://api.mailgun.net/v3/routes/4e97c1b2ba8a48567f007fb6",
        auth=("api", "YOUR_API_KEY"))
def get_route
  RestClient.
    get("https://api:YOUR_API_KEY"\
        "@api.mailgun.net/v3/routes/"\
        "4e97c1b2ba8a48567f007fb6"){|response, request, result| response }
end
using System;
using System.IO;
using RestSharp;
using RestSharp.Authenticators;

public class GetRouteChunk
{

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

    public static IRestResponse GetRoute ()
    {
        RestClient client = new RestClient ();
        client.BaseUrl = new Uri ("https://api.mailgun.net/v3");
        client.Authenticator =
            new HttpBasicAuthenticator ("api",
                                        "YOUR_API_KEY");
        RestRequest request = new RestRequest ();
        request.Resource = "routes/{id}";
        request.AddUrlSegment ("id", "4e97c1b2ba8a48567f007fb6");
        return client.Execute (request);
    }

}
func GetRouteByID(domain, apiKey string) (Route, error) {
  mg := mailgun.NewMailgun(domain, apiKey, "")
  return mg.GetRouteByID("4e97c1b2ba8a48567f007fb6")
}

Sample response:

{
  "route": {
      "description": "Sample route",
      "created_at": "Wed, 15 Feb 2012 13:03:31 GMT",
      "actions": [
          "forward(\"http://myhost.com/messages/\")",
          "stop()"
      ],
      "priority": 0,
      "expression": "match_recipient(\".*@samples.mailgun.org\")",
      "id": "4f3bad2335335426750048c6"
  }
}

Sample payload for a store() webhook:

Content-Type: multipart/alternative; boundary="001a114490d2c5be3d05433e6d03"
Date: Fri, 9 Dec 2016 13:04:51 -0600
From: Excited User <user@samples.mailgun.com>
Message-Id: <CABPem2N_Ucj3wRRZnLVpVF_fRjkTBXHZReZC3zY-hHsRa=T51g@samples.mailgun.com>
Mime-Version: 1.0
Subject: Message Routes
To: hook@sandboxdb91ab935a414789809f96c91229a0ee.mailgun.org
X-Envelope-From: <user@samples.mailgun.com>
X-Mailgun-Incoming: Yes
X-Originating-Ip: [2001:xxx:xxxx:xxx::beef:93]
body-html: <div dir="ltr">Testing Mailgun&#39;s forwarded and stored message routes :)</div>
body-plain: Testing Mailgun's forwarded and stored message routes :)
domain: sandboxdb91ab935a414789809f96c91229a0ee.mailgun.org
from: Excited User <user@samples.mailgun.com>
message-headers: [["X-Mailgun-Incoming", "Yes"], ["X-Envelope-From", "<user@samples.mailgun.com>"], ["Mime-Version", "1.0"], ["X-Originating-Ip", "[2001:xxx:xxxx:xxx::beef:93]"], ["From", "Excited User <user@samples.mailgun.com>"], ["Date", "Fri, 9 Dec 2016 13:04:51 -0600"], ["Message-Id", "<CABPem2N_Ucj3wRRZnLVpVF_fRjkTBXHZReZC3zY-hHsRa=T51g@samples.mailgun.com>"], ["Subject", "Message Routes"], ["To", "hook@sandboxdb91ab935a414789809f96c91229a0ee.mailgun.org"], ["Content-Type", "multipart/alternative; boundary=\"001a114490d2c5be3d05433e6d03\""]]
message-url: https://si.api.mailgun.net/v3/domains/sandboxdb91ab935a414789809f96c91229a0ee.mailgun.org/messages/eyJwIjpmYWxzZSwiayI6IjFlOTZmNTkyLTAyOWItNDJkYi1iNjM5LTgzNTgwYzMxYjNhOCIsInMiOiIyMmNkYTRkZWFhIiwiYyI6InNhaWFkIn0=
recipient: hook@sandboxdb91ab935a414789809f96c91229a0ee.mailgun.org
sender: user@samples.mailgun.com
signature: 6ed72df4b5f00af436fff03730dc8bda31bf5800fdf431d1da5c0009a639d57e
stripped-html: <div dir="ltr">Testing Mailgun&#39;s forwarded and stored message routes :)</div>
stripped-signature:
stripped-text: Testing Mailgun's forwarded and stored message routes :)
subject: Message Routes
timestamp: 1481310293
token: f2a24f20007696fb23fd66ff0f59f17fac3f885324caaaec50

Sample payload for a forward() webhook:

Content-Type: multipart/alternative; boundary="001a114490d2c5be3d05433e6d03"
Date: Fri, 9 Dec 2016 13:04:51 -0600
From: Excited User <user@samples.mailgun.com>
Message-Id: <CABPem2N_Ucj3wRRZnLVpVF_fRjkTBXHZReZC3zY-hHsRa=T51g@samples.mailgun.com>
Mime-Version: 1.0
Subject: Message Routes
To: hook@sandboxdb91ab935a414789809f96c91229a0ee.mailgun.org
X-Envelope-From: <user@samples.mailgun.com>
X-Mailgun-Incoming: Yes
X-Originating-Ip: [2001:xxx:xxxx:xxx::beef:93]
body-html: <div dir="ltr">Testing Mailgun&#39;s forwarded and stored message routes :)</div>
body-plain: Testing Mailgun's forwarded and stored message routes :)
from: Excited User <user@samples.mailgun.com>
message-headers: [["X-Mailgun-Incoming", "Yes"], ["X-Envelope-From", "<user@samples.mailgun.com>"], ["Mime-Version", "1.0"], ["X-Originating-Ip", "[2001:xxx:xxxx:xxx::beef:93]"], ["From", "Excited User <user@samples.mailgun.com>"], ["Date", "Fri, 9 Dec 2016 13:04:51 -0600"], ["Message-Id", "<CABPem2N_Ucj3wRRZnLVpVF_fRjkTBXHZReZC3zY-hHsRa=T51g@samples.mailgun.com>"], ["Subject", "Message Routes"], ["To", "hook@sandboxdb91ab935a414789809f96c91229a0ee.mailgun.org"], ["Content-Type", "multipart/alternative; boundary=\"001a114490d2c5be3d05433e6d03\""]]
recipient: hook@sandboxdb91ab935a414789809f96c91229a0ee.mailgun.org
sender: user@samples.mailgun.com
signature: 17436304dd4dd094e9b8c3addb975acc6297718da468c2900dac4a43787c97596
stripped-html: <div dir="ltr">Testing Mailgun&#39;s forwarded and stored message routes :)</div>
stripped-signature:
stripped-text: Testing Mailgun's forwarded and stored message routes :)
subject: Message Routes
timestamp: 1481310293
token: a71d0000ed34da6768198da96f9daaf8fb98adbccfdbd2fdaf