How to start tracking email events

Once you start sending and receiving messages, it’s important to track what’s happening with them. Mailgun provides a variety of methods to access data about your emails, which you can read more about in the Tracking Messages section of the User Manual. Below is a brief summary of Events, the Events API and Events Webhooks.

Events

Mailgun keeps track of every event that happens to every message (both inbound and outbound) and stores this data for at least 30 days for paid accounts and 2 days for free accounts.

Below is the table of events that Mailgun tracks.

Event Description
accepted Mailgun accepted the request to send/forward the email and the message has been placed in queue.
rejected Mailgun rejected the request to send/forward the email.
delivered Mailgun sent the email and it was accepted by the recipient email server.
failed Mailgun could not deliver the email to the recipient email server.
opened The email recipient opened the email and enabled image viewing. Open tracking must be enabled in the Mailgun control panel, and the CNAME record must be pointing to mailgun.org.
clicked The email recipient clicked on a link in the email. Click tracking must be enabled in the Mailgun control panel, and the CNAME record must be pointing to mailgun.org.
unsubscribed The email recipient clicked on the unsubscribe link. Unsubscribe tracking must be enabled in the Mailgun control panel.
complained The email recipient clicked on the spam complaint button within their email client. Feedback loops enable the notification to be received by Mailgun.
stored Mailgun has stored an incoming message

You can access Events through a few interfaces:

  • Webhooks (we POST data to your URL).
  • The Events API (you GET data through the API).
  • The Logs Tab of the Control Panel (GUI).

Events API

You can programmatically query and download events through the Events API:

curl -s --user 'api:YOUR_API_KEY' -G \
      https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/events \
      --data-urlencode begin='Fri, 3 May 2013 09:00:00 -0000' \
      --data-urlencode ascending=yes \
      --data-urlencode limit=25 \
      --data-urlencode pretty=yes \
      --data-urlencode recipient=joe@example.com
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 GetLogs() {

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

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

        return mgRoot
            .path("/{domain}/events")
            .resolveTemplate("domain", "YOUR_DOMAIN_NAME")
            .queryParam("begin", 50);
            .queryParam("ascending", "yes");
            .queryParam("limit", 1);
            .queryParam("pretty", "yes");
            .queryParam("recipient", "joe@example.com");
            .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');
$domain = 'YOUR_DOMAIN_NAME';
$queryString = array(
    'begin'        => 'Fri, 3 May 2013 09:00:00 -0000',
    'ascending'    => 'yes',
    'limit'        =>  25,
    'pretty'       => 'yes',
    'subject'      => 'test'
);

# Make the call to the client.
$result = $mgClient->get("$domain/events", $queryString);
def get_logs():
    return requests.get(
        "https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/events",
        auth=("api", "YOUR_API_KEY"),
        params={"begin"       : "Fri, 3 May 2013 09:00:00 -0000",
                "ascending"   : "yes",
                "limit"       :  25,
                "pretty"      : "yes",
                "recipient" : "joe@example.com"})
def get_logs
  RestClient.get "https://api:YOUR_API_KEY"\
  "@api.mailgun.net/v3/YOUR_DOMAIN_NAME/events",
   :params => {
    :'begin'       => 'Fri, 3 May 2013 09:00:00 -0000',
    :'ascending'   => 'yes',
    :'limit'       =>  25,
    :'pretty'      => 'yes',
    :'recipient' => 'joe@example.com'
   }
end
using System;
using System.IO;
using RestSharp;
using RestSharp.Authenticators;

public class EventsDateTimeRecipientChunk
{

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

    public static IRestResponse EventsDateTimeRecipient ()
    {
        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.AddParameter ("domain", "YOUR_DOMAIN_NAME", ParameterType.UrlSegment);
        request.Resource = "{domain}/events";
        request.AddParameter ("begin", "Fri, 3 May 2013 09:00:00 -0000");
        request.AddParameter ("ascending", "yes");
        request.AddParameter ("limit", 25);
        request.AddParameter ("pretty", "yes");
        request.AddParameter ("recipient", "joe@example.com");
        return client.Execute (request);
    }

}
func GetLog(domain, apiKey string) ([]mailgun.Event, error) {
  mg := mailgun.NewMailgun(domain, apiKey, "")
  ei := mg.NewEventIterator()
  err := ei.GetFirstPage(mailgun.GetEventsOptions{
    Begin:          time.Now().Add(-50 * Time.Minute),
    ForceAscending: true,
    Limit:          1,
    Filter:         map[string]string{
      "recipient": "joe@example.com",
    }
  })
  if err != nil {
    return nil, err
  }
  return ei.Events(), nil
}

Sample response:

{
  "items": [
    {
      "tags": [],
      "timestamp": 1376325780.160809,
      "envelope": {
        "sender": "me@samples.mailgun.org",
        "transport": ""
      },
      "event": "accepted",
      "campaigns": [],
      "user-variables": {},
      "flags": {
        "is-authenticated": true,
        "is-test-mode": false
      },
      "message": {
        "headers": {
          "to": "user@example.com",
          "message-id": "20130812164300.28108.52546@samples.mailgun.org",
          "from": "Excited User <me@samples.mailgun.org>",
          "subject": "Hello"
        },
        "attachments": [],
        "recipients": [
          "user@example.com"
        ],
        "size": 69
      },
      "recipient": "user@example.com",
      "method": "http"
    }
  ],
  "paging": {
    "next":
        "https://api.mailgun.net/v3/samples.mailgun.org/events/W3siY...",
    "previous":
        "https://api.mailgun.net/v3/samples.mailgun.org/events/Lkawm..."
  }
}

Events Webhooks

Mailgun can also make an HTTP POST to your URLs when events occur with your messages. If you would like Mailgun to POST event notifications, you need to provide a callback URL in the respective tab of the Control Panel. Webhooks are at the domain level so you can provide a unique URL for each domain by using the domain drop down selector.

You can read more about the data that is posted in the Webhooks section of the User Manual. We recommend using http://bin.mailgun.net for creating temporary URLs to test and debug your webhooks.

Other Goodies

In addition to sending, receiving and storing mail, Mailgun can also help developers with the following:

  • Automatic “Unsubscribe me” functionality.
  • Support for email campaigns and tracking their performance.
  • Bounce handling.
  • Spam complaints handling.
  • Spam filtering for incoming messages.
  • Searchable email logs.

The list of what Mailgun can do for you is growing every day. Please take a look at our User Manual to learn more.