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 com.mailgun.api.v3.MailgunEventsApi;
import com.mailgun.model.events.EventsQueryOptions;
import com.mailgun.model.events.EventsResponse;
import java.time.ZoneId;
import java.time.ZonedDateTime;
// ...
public EventsResponse getEvents() {
MailgunEventsApi mailgunEventsApi = MailgunClient.config(API_KEY)
.createApi(MailgunEventsApi.class);
EventsQueryOptions eventsQueryOptions = EventsQueryOptions.builder()
.begin(ZonedDateTime.now().minusDays(5))
.ascending(true)
.limit(1)
.build();
return mailgunEventsApi.getEvents(YOUR_DOMAIN_NAME, eventsQueryOptions);
}
# 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');
$domain = 'YOUR_DOMAIN_NAME';
$queryString = array(
'begin' => 'Wed, 1 Jan 2020 09:00:00 -0000',
'ascending' => 'yes',
'limit' => 25,
'pretty' => 'yes',
'recipient' => 'bob@example.com'
);
# Issue the call to the client.
$result = $mgClient->events()->get($domain, $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);
}
}
import (
"context"
"github.com/mailgun/mailgun-go/v3"
"time"
)
func PrintEventLog(domain, apiKey string) error {
mg := mailgun.NewMailgun(domain, apiKey)
// Create an iterator
it := mg.ListEvents(&mailgun.ListEventOptions{
Begin: time.Now().Add(-50 * time.Minute),
Limit: 100,
Filter: map[string]string{
"recipient": "joe@example.com",
},
})
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
defer cancel()
// Iterate through all the pages of events
var page []mailgun.Event
for it.Next(ctx, &page) {
for _, event := range page {
fmt.Printf("%+v\n", event)
}
}
// Did iteration end because of an error?
if it.Err() != nil {
return it.Err()
}
return nil
}
const DOMAIN = 'YOUR_DOMAIN_NAME';
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 date = new Date(2021, 10, 1, 0, 0, 0, 0); // Mon Nov 01 2021 00:00:00 GMT+0200
const events = await client.events.get(DOMAIN, {
begin: date.toGMTString(), // Sun, 31 Oct 2021 22:00:00 GMT
ascending: 'yes',
limit: 5
});
console.log('events', events)
} catch (error) {
console.error(error);
}
})();
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 via tags.
- 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.