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.mailgun.api.v3.suppression.MailgunSuppressionBouncesApi;
import com.mailgun.model.suppression.bounces.BouncesResponse;
// ...
public BouncesResponse getBounces() {
MailgunSuppressionBouncesApi suppressionBouncesApi = MailgunClient.config(API_KEY)
.createApi(MailgunSuppressionBouncesApi.class);
return suppressionBouncesApi.getBounces(YOUR_DOMAIN_NAME);
}
# 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()->bounces()->index($domain);
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);
}
}
import (
"context"
"github.com/mailgun/mailgun-go/v3"
"time"
)
func ListBounces(domain, apiKey string) ([]mailgun.Bounce, error) {
mg := mailgun.NewMailgun(domain, apiKey)
it := mg.ListBounces(nil)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
defer cancel()
var page, result []mailgun.Bounce
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 bounces = await client.suppressions.list(DOMAIN, 'bounces');
console.log('bounces', bounces);
} catch (error) {
console.error(error);
}
})();
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.mailgun.api.v3.suppression.MailgunSuppressionBouncesApi;
import com.mailgun.model.suppression.bounces.BouncesItem;
// ...
public BouncesItem getBounce() {
MailgunSuppressionBouncesApi suppressionBouncesApi = MailgunClient.config(API_KEY)
.createApi(MailgunSuppressionBouncesApi.class);
return suppressionBouncesApi.getBounce(YOUR_DOMAIN_NAME, "foo@bar.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()->bounces()->show($domain, $recipient);
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);
}
}
import (
"context"
"github.com/mailgun/mailgun-go/v3"
"time"
)
func GetBounce(domain, apiKey string) (mailgun.Bounce, error) {
mg := mailgun.NewMailgun(domain, apiKey)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
defer cancel()
return mg.GetBounce(ctx, "foo@bar.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 bouncesForAddress = await client.suppressions.get(DOMAIN, 'bounces', 'foo@bar.com');
console.log('bouncesForAddress', bouncesForAddress);
} catch (error) {
console.error(error);
}
})();
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.mailgun.api.v3.suppression.MailgunSuppressionBouncesApi;
import com.mailgun.model.suppression.SuppressionResponse;
import com.mailgun.model.suppression.bounces.BouncesRequest;
import java.time.ZonedDateTime;
// ...
public SuppressionResponse addBounce() {
MailgunSuppressionBouncesApi suppressionBouncesApi = MailgunClient.config(API_KEY)
.createApi(MailgunSuppressionBouncesApi.class);
BouncesRequest bouncesRequest = BouncesRequest.builder()
.address("bob@example.com")
.code("550")
.error(ERROR_MESSAGE)
.createdAt(ZonedDateTime.now())
.build();
return suppressionBouncesApi.addBounce(YOUR_DOMAIN_NAME, bouncesRequest);
}
# 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()->bounces()->create($domain, $recipient);
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);
}
}
import (
"context"
"github.com/mailgun/mailgun-go/v3"
"time"
)
func AddBounce(domain, apiKey string) error {
mg := mailgun.NewMailgun(domain, apiKey)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
defer cancel()
return mg.AddBounce(ctx, "bob@example.com", "550", "Undeliverable message error")
}
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 createdBounce = await client.suppressions.create(DOMAIN, 'bounces', { address: 'bob@example.com' });
console.log('createdBounce', createdBounce);
} catch (error) {
console.error(error);
}
})();
Sample response:
{
"message": "Address has been added to the bounces table",
"address": "bob@example.com"
}