Mailgun collects many different events and generates event statistics which are available in your Control Panel. This data is also available via our stats API endpoint. The stats endpoint is available at:


The statistics are calculated in hourly, daily and monthly resolution in UTC timezone.

GET /<domain>/stats/total

Returns total stats for a given domain.

Parameter Description
event The type of the event. For a complete list of all events written to the log see the Event Types table below. (Required)
start The starting time. Should be in RFC 2822#page-14 or unix epoch format. Default: 7 days from the current time.
end The ending date. Should be in RFC 2822#page-14 or unix epoch format. Default: current time.
resolution Can be either hour, day or month. Default: day
duration Period of time with resoluton encoded. See Duration for more info. If provided, overwrites the start date.

Data Retention

The following retention policy is applied to the statistics:

  • Hourly stats are preserved for two months.
  • Daily stats are preserved for a year.
  • Monthly stats are stored throughout the lifespan of the domain.


Duration is a string that represents a period of time with some resolution. It has a format [0-9]+[m,d,h] where

  • h - an hour
  • d - a day
  • m - a month


  • 24h - a period of 24 hours (a day) with hourly resolution
  • 1d - a period of 1 day with daily resolution
  • 2m - a period of 2 months with monthly resolution

Event Types

Mailgun tracks all of the events that occur throughout the system. Below are listed the events that you can retrieve using this API.

Event Type Description
accepted Mailgun accepted the request to send/forward the email and the message has been placed in queue.
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
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
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


Allows for grouping metrics by group type.

  • total
  • time
  • day
  • month
  • domain
  • ip
  • provider
  • tag
  • country
  • subaccount
  • ip_pool
GET /v3/stats/filter?event=delivered&group=provider

Filter by Subaccount

Use the subaccount ID to filter stats to a specific subaccount

GET /v3/stats/filter?event=delivered&filter=subaccount:<Subaccount ID>

Filter by IP Pool

Use the IP Pool ID to filter stats to a specific IP Pool

GET /v3/stats/filter?event=delivered&filter=ip_pool:<IP Pool ID>


Get stats for ‘accepted’, ‘delivered’, and ‘failed’ events for the past month:

curl -s --user 'api:YOUR_API_KEY' -G \ \
   -d event='accepted' \
   -d event='delivered' \
   -d event='failed' \
   -d duration='1m'
import java.util.List;

import com.mailgun.api.v3.MailgunStatisticsApi;
import com.mailgun.enums.Duration;
import com.mailgun.enums.ResolutionPeriod;
import com.mailgun.enums.StatsEventType;
import com.mailgun.model.StatisticsOptions;
import com.mailgun.model.stats.StatsResult;

// ...

public StatsResult getStats() {
    MailgunStatisticsApi mailgunStatisticsApi = MailgunClient.config(API_KEY)

    StatisticsOptions statsOptions = StatisticsOptions.builder()
        .event(List.of(StatsEventType.ACCEPTED, StatsEventType.DELIVERED))
        .duration(3, Duration.MONTH)

    return mailgunStatisticsApi.getDomainStats(YOUR_DOMAIN_NAME, statsOptions);
# 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';

# Define your Event types
$params = array(
  "event" => ["accepted", "delivered", "failed", "complained"]

$response = $mgClient->stats()->total($domain, $params);

def get_stats():
    return requests.get(
        auth=("api", "YOUR_API_KEY"),
        params={"event": ["accepted", "delivered", "failed"],
                "duration": "1m"})
def get_stats
  url_params = {}
  url_params[:duration] = "1m"
  url_params[:event] = []
  url_params[:event] << "accepted"
  url_params[:event] << "delivered"
  url_params[:event] << "failed"
  query_string = url_params.collect {|k, v| "#{k.to_s}=#{CGI::escape(v.to_s)}"}.
  RestClient.get "https://api:YOUR_API_KEY"\
using System;
using System.IO;
using RestSharp;
using RestSharp.Authenticators;

public class GetStatsChunk

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

    public static IRestResponse GetStats ()
        RestClient client = new RestClient ();
        client.BaseUrl = new Uri ("");
        client.Authenticator =
            new HttpBasicAuthenticator ("api",
        RestRequest request = new RestRequest ();
        request.AddParameter ("domain", "YOUR_DOMAIN_NAME", ParameterType.UrlSegment);
        request.Resource = "{domain}/stats/total";
        request.AddParameter ("event", "accepted");
        request.AddParameter ("event", "delivered");
        request.AddParameter ("event", "failed");
        request.AddParameter ("duration", "1m");
        return client.Execute (request);

import (

func GetStats(domain, apiKey string) ([]mailgun.Stats, error) {
    mg := mailgun.NewMailgun(domain, apiKey)

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

    return mg.GetStats(ctx, []string{"accepted", "delivered", "failed"}, &mailgun.GetStatOptions{
        Duration: "1m",

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 statsForDomain = await client.stats.getDomain(DOMAIN,{ 'event': ['accepted', 'delivered', 'failed'], 'duration': '1m'})
    console.log('statsForDomain', statsForDomain);
  } catch (error) {

Sample response:

  "end": "Fri, 01 Apr 2012 00:00:00 UTC",
  "resolution": "month",
  "start": "Tue, 14 Feb 2012 00:00:00 UTC",
  "stats": [
      "time": "Tue, 14 Feb 2012 00:00:00 UTC",
      "accepted": {
        "outgoing": 10,  // authenticated
        "incoming": 5,   // unauthenticated
        "total": 15
      "delivered": {
          "smtp": 15,  // delivered over SMTP
          "http": 5,   // delivered over HTTP
          "total": 20
      "failed": {
        "permanent": {
          "bounce": 4,
          "delayed-bounce": 1,
          "suppress-bounce": 1,       // recipients previously bounced
          "suppress-unsubscribe": 2,  // recipients previously unsubscribed
          "suppress-complaint": 3,    // recipients previously complained
          "total": 10                 // failed permanently and dropped
        "temporary": {
          "espblock": 1,   // failed temporary due to ESP block, will be retried
          "total": 1