Bounces

Mailgun automatically handles bounced emails. The bounced addresses are collected in a bounces list and subsequent delivery attempts are ignored to protect your sending reputation.

Mailgun can notify your application every time a message bounces.

The list of bounced addresses can be accessed programmatically:

GET /<domain>/bounces

Fetches the list of bounces.

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

Fetches a single bounce event by a given email address. This is useful to check if a given email address has bounced before.

POST /<domain>/bounces

Adds a permanent bounce to the bounces table. Updates the existing record if already here.

Parameter Description
address Valid email address
code Error code (default 550)
error Error description, (default is empty)
DELETE /<domain>/bounces/<address>

“Clears” a given bounce event.

Examples

Fetch the full list of all recipient addresses that bounced:

curl -s --user 'api:YOUR_API_KEY' -G \
  https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/bounces
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.JsonNode;
import com.mashape.unirest.http.Unirest;
import com.mashape.unirest.http.exceptions.UnirestException;

public class MGSample {

    // ...

    public static JsonNode getBounces() throws UnirestException {

        HttpResponse <JsonNode> request = Unirest.get("https://api.mailgun.net/v3/" + YOUR_DOMAIN_NAME + "/bounces")
            .basicAuth("api", API_KEY)
            .asJson();

        return request.getBody();
    }
}
# 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';

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

public class GetBouncesChunk
{

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

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

}
func GetBounces(domain, apiKey string) (int, []mailgun.Bounce, error) {
  mg := mailgun.NewMailgun(domain, apiKey, "")
  total, bounces, err := mg.GetBounces(-1, -1)
  return total, bounces, err
}
var DOMAIN = 'YOUR_DOMAIN_NAME';
var mailgun = require('mailgun-js')({ apiKey: "YOUR_API_KEY", domain: DOMAIN });

mailgun.get(`/${DOMAIN}/bounces/`, function (error, body) {
  console.log(body);
});

Sample JSON response is shown below. Notice the following:

  • There was only one bounce
  • Both SMTP error code and SMTP error message are preserved
{
  "total_count": 1,
  "items": [
      {
          "created_at": "Fri, 21 Oct 2011 11:02:55 GMT",
          "code": 550,
          "address": "'baz@example.com",
          "error": "Message was not accepted -- invalid mailbox.  Local mailbox 'baz@example.com is unavailable: user not found"
      }
  ]
}

Lets check if any messages sent to foo@bar.com have bounced before:

curl -s --user 'api:YOUR_API_KEY' -G \
    https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/bounces/foo@bar.com
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.JsonNode;
import com.mashape.unirest.http.Unirest;
import com.mashape.unirest.http.exceptions.UnirestException;

public class MGSample {

    // ...

    public static JsonNode getSingleBounce() throws UnirestException {

        HttpResponse <JsonNode> request = Unirest.get("https://api.mailgun.net/v3/" + YOUR_DOMAIN_NAME + "/bounces/foo@bar.com")
                       .basicAuth("api", API_KEY)
            .asJson();

        return request.getBody();
    }
}
# 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';
$bounce = 'bob@example.com';

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

public class GetBounceChunk
{

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

    public static IRestResponse GetBounce ()
    {
        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}/bounces/foo@bar.com";
        return client.Execute (request);
    }

}
func GetBounce(domain, apiKey string) (mailgun.Bounce, error) {
  mg := mailgun.NewMailgun(domain, apiKey, "")
  return mg.GetSingleBounce("foo@bar.com")
}
var DOMAIN = 'YOUR_DOMAIN_NAME';
var mailgun = require('mailgun-js')({ apiKey: "YOUR_API_KEY", domain: DOMAIN });

mailgun.get(`/${DOMAIN}/bounces`, function (error, body) {
  console.log(body);
});

Sample response:

{
  "message": "Address not found in bounces table"
}

Add a bounce to the table:

curl -s --user 'api:YOUR_API_KEY' \
    https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/bounces \
    -F address='bob@example.com'
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.JsonNode;
import com.mashape.unirest.http.Unirest;
import com.mashape.unirest.http.exceptions.UnirestException;

public class MGSample {

    // ...

    public static JsonNode addBounce() throws UnirestException {

        HttpResponse <JsonNode> request =  Unirest.post("https://api.mailgun.net/v3/" + YOUR_DOMAIN_NAME + "/bounces")
            .basicAuth("api", API_KEY)
            .field("address", "bob@example.com")
            .asJson();

        return request.getBody();
    }
}
# 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';

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

public class AddBounceChunk
{

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

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

}
func AddBounce(domain, apiKey) error {
  mg := mailgun.NewMailgun(domain, apiKey, "")
  return mg.AddBounce("bob@example.com", "550", "Undeliverable message error")
}
var DOMAIN = 'YOUR_DOMAIN_NAME';
var mailgun = require('mailgun-js')({ apiKey: "YOUR_API_KEY", domain: DOMAIN });

mailgun.post(`/${DOMAIN}/bounces`, {'address': 'bob@example.com'}, function (error, body) {
  console.log(body);
});

Sample response:

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