Spam Complaints

When recipients of your messages press “Spam” button, Mailgun receives those complaints from ESPs (email service providers).

Mailgun can notify your application every time a recipient flags your message as spam.

This API allows you to programmatically download the list of users who have complained, add a complaint, or delete a complaint.

GET /<domain>/complaints

Fetches the list of complaints.

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

Fetches a single spam complaint by a given email address. This is useful to check if a particular user has complained.

POST /<domain>/complaints

Adds an address to the complaints table.

Parameter Description
address Valid email address
DELETE /<domain>/complaints/<address>

Removes a given spam complaint.

Examples

Fetch the full list of all recipients who have pressed their “Spam” buttons:

curl -s --user 'api:YOUR_API_KEY' -G \
    https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/complaints
import com.mailgun.api.v3.suppression.MailgunSuppressionComplaintsApi;
import com.mailgun.model.suppression.complaints.ComplaintsItemResponse;

// ...

public ComplaintsItemResponse getComplaints() {
    MailgunSuppressionComplaintsApi suppressionComplaintsApi = MailgunClient.config(API_KEY)
        .createApi(MailgunSuppressionComplaintsApi.class);

    return suppressionComplaintsApi.getAllComplaints(YOUR_DOMAIN_NAME, 2);
}
# 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';

# Issue the call to the client.
$result = $mgClient->suppressions()->complaints()->index($domain);
def get_complaints():
    return requests.get(
        "https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/complaints",
        auth=("api", "YOUR_API_KEY"))
def get_complaints
  RestClient.get "https://api:YOUR_API_KEY"\
  "@api.mailgun.net/v3/YOUR_DOMAIN_NAME/complaints"
end
using System;
using System.IO;
using RestSharp;
using RestSharp.Authenticators;

public class GetComplaintsChunk
{

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

    public static IRestResponse GetComplaints ()
    {
        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}/complaints";
        return client.Execute (request);
    }

}
import (
    "context"
    "github.com/mailgun/mailgun-go/v3"
    "time"
)

func ListComplaints(domain, apiKey string) ([]mailgun.Complaint, error) {
    mg := mailgun.NewMailgun(domain, apiKey)
    it := mg.ListComplaints(nil)

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

    var page, result []mailgun.Complaint
    for it.Next(ctx, &page) {
        result = append(result, page...)
    }

    if it.Err() != nil {
        return nil, it.Err()
    }
    return result, nil
}
const DOMAIN = 'YOUR_DOMAIN_NAME';

const formData = require('form-data');
const Mailgun = require('mailgun.js');

const mailgun = new Mailgun(formData);

const client = mailgun.client({ username: 'api', key: 'YOUR_API_KEY' || '' });
(async () => {
  try {
    const complaints = await client.suppressions.list(DOMAIN, 'complaints');
    console.log('complaints', complaints);
  } catch (error) {
    console.error(error);
  }
})();

Sample JSON response is shown below. Notice the following:

  • There was only one user who clicked “Spam” button.
  • According to count value, he clicked twice.
  • created_at indicates the time when it happened.
{
  "total_count": 1,
  "items": [
      {
          "count": 2,
          "created_at": "Tue, 15 Nov 2011 08:25:11 GMT",
          "address": "baz@example.com"
      }
  ]
}

Now lets check if baz@example.com ever complained:

curl -s --user 'api:YOUR_API_KEY' -G \
   https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/complaints/baz@example.com
import com.mailgun.api.v3.suppression.MailgunSuppressionComplaintsApi;
import com.mailgun.model.suppression.complaints.ComplaintsItem;

// ...

public ComplaintsItem getComplaint() {
    MailgunSuppressionComplaintsApi suppressionComplaintsApi = MailgunClient.config(API_KEY)
        .createApi(MailgunSuppressionComplaintsApi.class);

    return suppressionComplaintsApi.getSingleComplaint(YOUR_DOMAIN_NAME, "baz@example.com");
}
# 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';
$recipient = 'bob@example.com';

# Issue the call to the client.
$result = $mgClient->suppressions()->complaints()->show($domain, $recipient);
def get_complaint():
    return requests.get(
        "https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/complaints/baz@example.com",
        auth=("api", "YOUR_API_KEY"))
def get_complaint
  RestClient.get("https://api:YOUR_API_KEY"\
                 "@api.mailgun.net/v3/YOUR_DOMAIN_NAME/complaints/"\
                 "baz@example.com"){|response, request, result| response }
end
using System;
using System.IO;
using RestSharp;
using RestSharp.Authenticators;

public class GetComplaintChunk
{

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

    public static IRestResponse GetComplaint ()
    {
        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}/complaints/baz@example.com";
        return client.Execute (request);
    }

}
import (
    "context"
    "github.com/mailgun/mailgun-go/v3"
    "time"
)

func GetComplaints(domain, apiKey string) (mailgun.Complaint, error) {
    mg := mailgun.NewMailgun(domain, apiKey)

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

    return mg.GetComplaint(ctx, "baz@example.com")
}
const DOMAIN = 'YOUR_DOMAIN_NAME';

const formData = require('form-data');
const Mailgun = require('mailgun.js');

const mailgun = new Mailgun(formData);

const client = mailgun.client({ username: 'api', key: 'YOUR_API_KEY' || '' });
(async () => {
  try {
    const complaintsForAddress = await client.suppressions.get(DOMAIN, 'complaints', 'baz@example.com');
    console.log('complaintsForAddress', complaintsForAddress);
  } catch (error) {
    console.error(error);
  }
})();

Of course he did. The response:

{
  "complaint": {
      "count": 2,
      "created_at": "Tue, 15 Nov 2011 08:25:11 GMT",
      "address": "baz@example.com"
  }
}

Add a complaint to the table:

curl -s --user 'api:YOUR_API_KEY' \
   https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/complaints \
   -F address='bob@example.com'
import com.mailgun.api.v3.suppression.MailgunSuppressionComplaintsApi;
import com.mailgun.model.suppression.SuppressionResponse;
import com.mailgun.model.suppression.complaints.ComplaintsSingleItemRequest;

import java.time.ZonedDateTime;

// ...

public SuppressionResponse addComplaint() {
    MailgunSuppressionComplaintsApi suppressionComplaintsApi = MailgunClient.config(API_KEY)
        .createApi(MailgunSuppressionComplaintsApi.class);

    ComplaintsSingleItemRequest complaintsSingleItemRequest = ComplaintsSingleItemRequest.builder()
        .address( "bob@example.com")
        .createdAt(ZonedDateTime.now())
        .build();

    return suppressionComplaintsApi.addAddressToComplaintsList(YOUR_DOMAIN_NAME, complaintsSingleItemRequest);
}
# 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';
$recipient = 'bob@example.com';

# Issue the call to the client.
$result = $mgClient->suppressions()->complaints()->create($domain, $recipient);
def add_complaint():
    return requests.post(
        "https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/complaints",
        auth=("api", "YOUR_API_KEY"),
        data={'address': 'bob@example.com'})
def add_complaint
  RestClient.post "https://api:YOUR_API_KEY"\
  "@api.mailgun.net/v3/YOUR_DOMAIN_NAME/complaints",
  :address => 'bob@example.com'
end
using System;
using System.IO;
using RestSharp;
using RestSharp.Authenticators;

public class AddComplaintChunk
{

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

    public static IRestResponse AddComplaint ()
    {
        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 = "{domain}/complaints";
        request.AddParameter ("domain", "YOUR_DOMAIN_NAME", ParameterType.UrlSegment);
        request.AddParameter ("address", "bob@example.com");
        request.Method = Method.POST;
        return client.Execute (request);
    }

}
import (
    "context"
    "github.com/mailgun/mailgun-go/v3"
    "time"
)

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

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

    return mg.CreateComplaint(ctx, "bob@example.com")
}
const DOMAIN = 'YOUR_DOMAIN_NAME';

const formData = require('form-data');
const Mailgun = require('mailgun.js');

const mailgun = new Mailgun(formData);

const client = mailgun.client({ username: 'api', key: 'YOUR_API_KEY' || '' });
(async () => {
    try {
        const createdComplaint = await client.suppressions.create(DOMAIN, 'complaints', { address: 'bob@example.com' });
        console.log('createdComplaint', createdComplaint);
    } catch (error) {
        console.error(error);
    }
})();

Sample response:

{
  "message": "Address has been added to the complaints table",
  "address": "bob@example.com"
}