Messages

Sending

There are two ways to send emails using Mailgun API:

v3/<domain>/messages
  • You can pass the components of the messages such as To, From, Subject, HTML and text parts, attachments, etc. Mailgun will build a MIME representation of the message and send it. This is the preferred method.
v3/<domain>/messages.mime
  • You can also build a MIME string yourself using a MIME library for your programming language and submit it to Mailgun.

Note

  • Sending options (those prefixed by o:, h:, or v:) are limited to 16 kB in total.
  • Mailgun supports maximum messages size of 25MB.
  • You can also use good old SMTP to send messages. But you will have to specify all advanced sending options via MIME headers
  • HTTP send will error with “parameter is not a valid address” if the provided email address fails syntax checks in accordance with RFC5321, RFC5322, RFC6854.
POST /<domain>/messages

Sends a message by assembling it from the components. Note that you can specify most parameters multiple times, HTTP supports this out of the box. This makes sense for parameters like cc, to or attachment.

Parameter Description
from Email address for From header
to Email address of the recipient(s). Example: "Bob <bob@host.com>". You can use commas to separate multiple recipients.
cc Same as To but for Cc
bcc Same as To but for Bcc
subject Message subject
text Body of the message. (text version)
html Body of the message. (HTML version)
amp-html AMP part of the message. Please follow google guidelines to compose and send AMP emails.
attachment File attachment. You can post multiple attachment values. Important: You must use multipart/form-data encoding when sending attachments.
inline Attachment with inline disposition. Can be used to send inline images (see example). You can post multiple inline values.
template Name of a template stored via template API. See Templates for more information
t:version Use this parameter to send a message to specific version of a template
t:text Pass yes if you want to have rendered template in the text part of the message in case of template sending
t:variables A valid JSON-encoded dictionary used as the input for template variable expansion See Templates for more information.
o:tag Tag string. See Tagging for more information.
o:dkim Enables/disables DKIM signatures on per-message basis. Pass yes, no, true or false
o:deliverytime Desired time of delivery. See Date Format. Note: Messages can be scheduled for a maximum of 3 days in the future.
o:deliverytime-optimize-period Toggles Send Time Optimization (STO) on a per-message basis. String should be set to the number of hours in [0-9]+h format, with the minimum being 24h and the maximum being 72h. This value defines the time window in which Mailgun will run the optimization algorithm based on prior engagement data of a given recipient. See Sending a message with STO for details. Please note that STO is only available on certain plans. See www.mailgun.com/pricing for more info.
o:time-zone-localize Toggles Timezone Optimization (TZO) on a per message basis. String should be set to preferred delivery time in HH:mm or hh:mmaa format, where HH:mm is used for 24 hour format without AM/PM and hh:mmaa is used for 12 hour format with AM/PM. See Sending a message with TZO for details. Please note that TZO is only available on certain plans. See www.mailgun.com/pricing for more info.
o:testmode Enables sending in test mode. Pass yes if needed. See Sending in Test Mode
o:tracking Toggles tracking on a per-message basis, see Tracking Messages for details. Pass yes, no, true or false
o:tracking-clicks Toggles clicks tracking on a per-message basis. Has higher priority than domain-level setting. Pass yes, no, true``or ``false.
o:tracking-opens Toggles opens tracking on a per-message basis. Has higher priority than domain-level setting. Pass yes or no, true or false
o:require-tls

If set to True or yes this requires the message only be sent over a TLS connection. If a TLS connection can not be established, Mailgun will not deliver the message.

If set to False or no, Mailgun will still try and upgrade the connection, but if Mailgun can not, the message will be delivered over a plaintext SMTP connection.

The default is False.

o:skip-verification

If set to True or yes, the certificate and hostname will not be verified when trying to establish a TLS connection and Mailgun will accept any certificate during delivery.

If set to False or no, Mailgun will verify the certificate and hostname. If either one can not be verified, a TLS connection will not be established.

The default is False.

h:X-My-Header h: prefix followed by an arbitrary value allows to append a custom MIME header to the message (X-My-Header in this case). For example, h:Reply-To to specify Reply-To address, h:X-Mailgun-Sending-Ip-Pool=123 to deliver the message with an IP address that is part of the IP pool identified by ID 123, or h:X-Mailgun-Sending-Ip-Pool=xx.xx.xxx.x to deliver the message with a specified IP address.
v:my-var v: prefix followed by an arbitrary name allows to attach a custom JSON data to the message. See Attaching Data to Messages for more information.
recipient-variables A valid JSON-encoded dictionary, where key is a plain recipient address and value is a dictionary with variables that can be referenced in the message body. See Batch Sending for more information.
POST /<domain>/messages.mime

Posts a message in MIME format. Note: you will need to build a MIME string yourself. Use a MIME library for your programming language to do this. Pass the resulting MIME string as message parameter.

Note

You must use multipart/form-data encoding.

Parameter Description
to Email address of the recipient(s). Example: "Bob <bob@host.com>". You can use commas to separate multiple recipients. Make sure to include all To, Cc and Bcc recipients of the message.
message MIME string of the message. Make sure to use multipart/form-data to send this as a file upload.
o:tag Tag string. See Tagging for more information.
o:deliverytime Desired time of delivery. See Date Format. Note: Messages can be scheduled for a maximum of 3 days in the future.
o:dkim Enables/disabled DKIM signatures on per-message basis. Pass yes or no
o:testmode Enables sending in test mode. Pass yes if needed. See Sending in Test Mode
o:tracking Toggles tracking on a per-message basis, see Tracking Messages for details. Pass yes or no.
o:tracking-clicks Toggles clicks tracking on a per-message basis. Has higher priority than domain-level setting. Pass yes or no.
o:tracking-opens Toggles opens tracking on a per-message basis. Has higher priority than domain-level setting. Pass yes or no.
h:X-My-Header h: prefix followed by an arbitrary value allows to append a custom MIME header to the message (X-My-Header in this case). For example, h:Reply-To to specify Reply-To address, h:X-Mailgun-Sending-Ip-Pool=123 to deliver the message with an IP address that is part of the IP pool identified by ID 123, or h:X-Mailgun-Sending-Ip-Pool=xx.xx.xxx.x to deliver the message with a specified IP address.
v:my-var v: prefix followed by an arbitrary name allows to attach a custom JSON data to the message. See Attaching Data to Messages for more information.

Retrieving Stored Messages

To retrieve an inbound message that has been stored via the store() action, use the URL found in the stored event (which you can find through the Events API, or in the notify webhook set when creating the store action (store(notify="http://mydomain.com/callback")).

  • By default the message will be returned in JSON form with parsed parts. Links to the attachments will be included.
  • You can also retrieve the full raw mime message (attachments and all) if you make the request to the URL with the Accept header set to message/rfc2822.
  • Stored messages are encoded with Quoted-printable encoding. Decoding samples are available in the examples section below.

These are the parameters of the JSON returned from a GET request to a stored message url.

Parameter Type Description
recipients string recipient of the message as reported by MAIL TO during SMTP chat.
sender string sender of the message as reported by MAIL FROM during SMTP chat. Note: this value may differ from From MIME header.
from string sender of the message as reported by From message header, for example “Bob Lee <blee@mailgun.net>”.
subject string subject string.
body-plain string text version of the email. This field is always present. If the incoming message only has HTML body, Mailgun will create a text representation for you.
stripped-text string text version of the message without quoted parts and signature block (if found).
stripped-signature string the signature block stripped from the plain text message (if found).
body-html string HTML version of the message, if message was multipart. Note that all parts of the message will be posted, not just text/html. For instance if a message arrives with “foo” part it will be posted as “body-foo”.
stripped-html string HTML version of the message, without quoted parts.
attachments string contains a json list of metadata objects, one for each attachment, see below.
message-headers string list of all MIME headers dumped to a json string (order of headers preserved).
content-id-map string JSON-encoded dictionary which maps Content-ID (CID) of each attachment to the corresponding attachment-x parameter. This allows you to map posted attachments to tags like <img src='cid'> in the message body.

Note

Do not rely on the body-plain, stripped-text, and stripped-signature fields for HTML sanitization. These fields merely provide content from the text/plain portion of an incoming message. This content may contain unescaped HTML.

The attachments JSON contains the following items.

Parameter Type Description
size integer indicates the size of the attachment in bytes.
url string contains the url where the attachment can be found. This does not support DELETE.
name string the name of the attachment
content-type string the content type of the attachment

These are the parameters when the Accept header is set to message/rfc2822

Parameter Type Description
recipients string recipient of the message.
sender string sender of the message as reported by SMTP MAIL FROM.
from string sender of the message as reported by From message header, for example “Bob <bob@example.com>”.
subject string subject string.
body-mime string full MIME envelope. You will need a MIME parsing library to process this data.

Deleting Stored Messages

Stored messages are retained in the system for 3 days and automatically purged after this retention period, therefore there is no need to delete messages explicitly.

Note

Mailgun reserves the right to impose a limit on the size and number of stored messages. In the event this is necessary, you will be notified in advance.

Examples

Warning

Some samples are using curl utility for API examples. UNIX shells require that some characters must be escaped, for example $ becomes \$.

If your API key contains unescaped characters you may receive HTTP error 401 (Unauthorized).

Sending a plain text message:

curl -s --user 'api:YOUR_API_KEY' \
    https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/messages \
    -F from='Excited User <mailgun@YOUR_DOMAIN_NAME>' \
    -F to=YOU@YOUR_DOMAIN_NAME \
    -F to=bar@example.com \
    -F subject='Hello' \
    -F text='Testing some Mailgun awesomeness!'
import com.mailgun.api.v3.MailgunMessagesApi;
import com.mailgun.model.message.Message;
import com.mailgun.model.message.MessageResponse;

// ...

public MessageResponse sendSimpleMessage() {
    MailgunMessagesApi mailgunMessagesApi = MailgunClient.config(API_KEY)
        .createApi(MailgunMessagesApi.class);

    Message message = Message.builder()
        .from("Excited User <USER@YOURDOMAIN.COM>")
        .to("artemis@example.com")
        .subject("Hello")
        .text("Testing out some Mailgun awesomeness!")
        .build();

    return mailgunMessagesApi.sendMessage(YOUR_DOMAIN_NAME, message);
}
# 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";
$params = array(
  'from'    => 'Excited User <YOU@YOUR_DOMAIN_NAME>',
  'to'      => 'bob@example.com',
  'subject' => 'Hello',
  'text'    => 'Testing some Mailgun awesomness!'
);

# Make the call to the client.
$mgClient->messages()->send($domain, $params);
def send_simple_message():
    return requests.post(
        "https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/messages",
        auth=("api", "YOUR_API_KEY"),
        data={"from": "Excited User <mailgun@YOUR_DOMAIN_NAME>",
              "to": ["bar@example.com", "YOU@YOUR_DOMAIN_NAME"],
              "subject": "Hello",
              "text": "Testing some Mailgun awesomness!"})
def send_simple_message
  RestClient.post "https://api:YOUR_API_KEY"\
  "@api.mailgun.net/v3/YOUR_DOMAIN_NAME/messages",
  :from => "Excited User <mailgun@YOUR_DOMAIN_NAME>",
  :to => "bar@example.com, YOU@YOUR_DOMAIN_NAME",
  :subject => "Hello",
  :text => "Testing some Mailgun awesomness!"
end
using System;
using System.IO;
using RestSharp;
using RestSharp.Authenticators;

public class SendSimpleMessageChunk
{

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

    public static IRestResponse SendSimpleMessage ()
    {
        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}/messages";
        request.AddParameter ("from", "Excited User <mailgun@YOUR_DOMAIN_NAME>");
        request.AddParameter ("to", "bar@example.com");
        request.AddParameter ("to", "YOU@YOUR_DOMAIN_NAME");
        request.AddParameter ("subject", "Hello");
        request.AddParameter ("text", "Testing some Mailgun awesomness!");
        request.Method = Method.POST;
        return client.Execute (request);
    }

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

func SendSimpleMessage(domain, apiKey string) (string, error) {
    mg := mailgun.NewMailgun(domain, apiKey)
    m := mg.NewMessage(
        "Excited User <mailgun@YOUR_DOMAIN_NAME>",
        "Hello",
        "Testing some Mailgun awesomeness!",
        "YOU@YOUR_DOMAIN_NAME",
    )

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

    _, id, err := mg.Send(ctx, m)
    return id, err
}
const API_KEY = 'YOUR_API_KEY';
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: API_KEY});

const messageData = {
  from: 'Excited User <me@samples.mailgun.org>',
  to: 'foo@example.com, bar@example.com',
  subject: 'Hello',
  text: 'Testing some Mailgun awesomeness!'
};

client.messages.create(DOMAIN, messageData)
 .then((res) => {
   console.log(res);
 })
 .catch((err) => {
   console.error(err);
 });

Sample response:

{
  "message": "Queued. Thank you.",
  "id": "<20111114174239.25659.5817@samples.mailgun.org>"
}

Sending a message with HTML and text parts. This example also attaches file to the message:

curl -s --user 'api:YOUR_API_KEY' \
    https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/messages \
    -F from='Excited User <YOU@YOUR_DOMAIN_NAME>' \
    -F to='foo@example.com' \
    -F cc='bar@example.com' \
    -F bcc='baz@example.com' \
    -F subject='Hello' \
    -F text='Testing some Mailgun awesomness!' \
    --form-string html='<html>HTML version of the body</html>' \
    -F attachment=@files/cartman.jpg \
    -F attachment=@files/cartman.png
import java.io.File;

import com.mailgun.api.v3.MailgunMessagesApi;
import com.mailgun.model.message.Message;
import com.mailgun.model.message.MessageResponse;

// ...

public MessageResponse sendComplexMessage() {
    MailgunMessagesApi mailgunMessagesApi = MailgunClient.config(API_KEY)
        .createApi(MailgunMessagesApi.class);

    Message message = Message.builder()
        .from("Excited User <USER@YOURDOMAIN.COM>")
        .to("alice@example.com")
        .cc("bob@example.com")
        .bcc("joe@example.com")
        .subject("Hello")
        .html("<html>HTML version </html>")
        .attachment(new File("/temp/folder/test.txt"))
        .build();

    return mailgunMessagesApi.sendMessage(YOUR_DOMAIN_NAME, message);
}
# 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";
$params = array(
      'from'    => 'Excited User <YOU@YOUR_DOMAIN_NAME>',
      'to'      => 'bob@example.com',
      'cc'      => 'alice@example.com',
      'bcc'     => 'john@example.com',
      'subject' => 'Hello',
      'text'    => 'Testing some Mailgun awesomness!',
      'html'    => '<html>HTML version of the body</html>',
      'attachment' => array(
              array(
                  'filePath' => 'test.txt',
                  'filename' => 'test_file.txt'
            )
        )
    );

# Make the call to the client.
$result = $mgClient->messages()->send($domain, $params);
def send_complex_message():
    return requests.post(
        "https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/messages",
        auth=("api", "YOUR_API_KEY"),
        files=[("attachment", ("test.jpg", open("files/test.jpg","rb").read())),
               ("attachment", ("test.txt", open("files/test.txt","rb").read()))],
        data={"from": "Excited User <YOU@YOUR_DOMAIN_NAME>",
              "to": "foo@example.com",
              "cc": "baz@example.com",
              "bcc": "bar@example.com",
              "subject": "Hello",
              "text": "Testing some Mailgun awesomness!",
              "html": "<html>HTML version of the body</html>"})
def send_complex_message
  data = {}
  data[:from] = "Excited User <YOU@YOUR_DOMAIN_NAME>"
  data[:to] = "foo@example.com"
  data[:cc] = "baz@example.com"
  data[:bcc] = "bar@example.com"
  data[:subject] = "Hello"
  data[:text] = "Testing some Mailgun awesomness!"
  data[:html] = "<html>HTML version of the body</html>"
  data[:attachment] = []
  data[:attachment] << File.new(File.join("files", "test.jpg"))
  data[:attachment] << File.new(File.join("files", "test.txt"))
  RestClient.post "https://api:YOUR_API_KEY"\
  "@api.mailgun.net/v3/YOUR_DOMAIN_NAME/messages", data
end
using System;
using System.IO;
using RestSharp;
using RestSharp.Authenticators;

public class SendComplexMessageChunk
{

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

    public static IRestResponse SendComplexMessage ()
    {
        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}/messages";
        request.AddParameter ("from", "Excited User <YOU@YOUR_DOMAIN_NAME>");
        request.AddParameter ("to", "foo@example.com");
        request.AddParameter ("cc", "baz@example.com");
        request.AddParameter ("bcc", "bar@example.com");
        request.AddParameter ("subject", "Hello");
        request.AddParameter ("text", "Testing some Mailgun awesomness!");
        request.AddParameter ("html",
                              "<html>HTML version of the body</html>");
        request.AddFile ("attachment", Path.Combine ("files", "test.jpg"));
        request.AddFile ("attachment", Path.Combine ("files", "test.txt"));
        request.Method = Method.POST;
        return client.Execute (request);
    }

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

func SendComplexMessage(domain, apiKey string) (string, error) {
    mg := mailgun.NewMailgun(domain, apiKey)
    m := mg.NewMessage(
        "Excited User <YOU@YOUR_DOMAIN_NAME>",
        "Hello",
        "Testing some Mailgun awesomeness!",
        "foo@example.com",
    )
    m.AddCC("baz@example.com")
    m.AddBCC("bar@example.com")
    m.SetHtml("<html>HTML version of the body</html>")
    m.AddAttachment("files/test.jpg")
    m.AddAttachment("files/test.txt")

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

    _, id, err := mg.Send(ctx, m)
    return id, err
}
import path from 'node:path';
import fs from 'node:fs/promises';

const API_KEY = 'YOUR_API_KEY';
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: API_KEY });

(async () => {
  const filepath = path.resolve('sample.jpg');
  try {
    const file = {
      filename: 'sample.jpg',
      data: await fs.readFile(filepath)
    };
    const attachment = [file];

    const data = {
      from: 'Excited User <me@samples.mailgun.org>',
      to: ['foo@example.com', 'baz@example.com', 'bar@example.com'],
      cc: 'baz@example.com',
      bcc: 'bar@example.com',
      subject: 'Complex',
      text: 'Testing some Mailgun awesomness!',
      html: '<html>HTML version of the body</html>',
      attachment
    };

    const result = await client.messages.create(DOMAIN, data);
    console.log(result);
  } catch (error) {
    console.error(error);
  }
})();

Sending a MIME message which you pre-build yourself using a MIME library of your choice:

curl -s --user 'api:YOUR_API_KEY' \
    https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/messages.mime \
    -F to='bob@example.com' \
    -F message=@files/message.mime
import java.io.File;
import com.mailgun.api.v3.MailgunMessagesApi;
import com.mailgun.client.MailgunClient;
import com.mailgun.model.message.MailgunMimeMessage;
import com.mailgun.model.message.MessageResponse;

// ...

public MessageResponse sendMIMEMessage() {
    MailgunMessagesApi mailgunMessagesApi = MailgunClient.config(API_KEY)
            .createApi(MailgunMessagesApi.class);


    MailgunMimeMessage mailgunMimeMessage = MailgunMimeMessage.builder()
            .to("megan@example.com)
            .message(new File("/path/to/file.mime"))
            .build();

    return mailgunMessagesApi.sendMIMEMessage(YOUR_DOMAIN_NAME, mailgunMimeMessage);
}
# 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";

$recipients = array(
    'bob@example.com',
    'alice@example.com',
    'john@example.com';
);
$params = array(
    'from' => 'Excited User <YOU@YOUR_DOMAIN_NAME>'
);

$mime_string = '<Pass fully formed MIME string here>'

# Make the call to the client.
$result = $mgClient->messages()->sendMime($domain, $recipients, $mime_string, $params);
def send_mime_message():
    return requests.post(
        "https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/messages.mime",
        auth=("api", "YOUR_API_KEY"),
        data={"to": "bar@example.com"},
        files={"message": open("files/message.mime")})
def send_mime_message
  RestClient.post "https://api:YOUR_API_KEY"\
  "@api.mailgun.net/v3/YOUR_DOMAIN_NAME/messages.mime",
  :to => "bar@example.com",
  :message => File.new(File.join("files", "message.mime"))
end
using System;
using System.IO;
using RestSharp;
using RestSharp.Authenticators;

public class SendMimeMessageChunk
{

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

    public static IRestResponse SendMimeMessage ()
    {
        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}/messages.mime";
        request.AddParameter ("to", "bar@example.com");
        request.AddFile ("message", Path.Combine ("files", "message.mime"));
        request.Method = Method.POST;
        return client.Execute (request);
    }

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

func SendMimeMessage(domain, apiKey string) (string, error) {
    mg := mailgun.NewMailgun(domain, apiKey)
    mimeMsgReader, err := os.Open("files/message.mime")
    if err != nil {
        return "", err
    }

    m := mg.NewMIMEMessage(mimeMsgReader, "bar@example.com")

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

    _, id, err := mg.Send(ctx, m)
    return id, err
}
const DOMAIN = 'YOUR_DOMAIN_NAME';
const API_KEY = 'YOUR_API_KEY';
import formData from 'form-data';
import Mailgun from 'mailgun.js';
import MailComposer from 'nodemailer/lib/mail-composer';

const mailgun = new Mailgun(formData);
const mg = mailgun.client({ username: 'api', key: API_KEY });

(async () => {
  const mailOptions = {
    from: 'YOU@YOUR_DOMAIN_NAME',
    to: 'bob@example.com',
    subject: 'Hello',
    text: 'Testing some Mailgun awesomeness!'
  };
  try {
    const mail = new MailComposer(mailOptions);
    const compiledMessage = await mail.compile().build();

    const res = await mg.messages.create(DOMAIN, {
      to: 'bob@example.com',
      message: compiledMessage
    });
    console.log(res);
  } catch (error) {
    console.error(error);
  }
})();

An example of how to toggle tracking on a per-message basis. Note the o:tracking option. This will disable link rewriting for this message:

curl -s --user 'api:YOUR_API_KEY' \
    https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/messages \
    -F from='Sender Bob <sbob@YOUR_DOMAIN_NAME>' \
    -F to='alice@example.com' \
    -F subject='Hello' \
    -F text='Testing some Mailgun awesomness!' \
    -F o:tracking=False
import com.mailgun.api.v3.MailgunMessagesApi;
import com.mailgun.model.message.Message;
import com.mailgun.model.message.MessageResponse;

// ...

public MessageResponse sendMessageNoTracking() {
    MailgunMessagesApi mailgunMessagesApi = MailgunClient.config(API_KEY)
        .createApi(MailgunMessagesApi.class);

    Message message = Message.builder()
        .from("Excited User <USER@YOURDOMAIN.COM>")
        .to("alice@example.com")
        .subject("Hello")
        .text("Testing out some Mailgun awesomeness!")
        .tracking(false)
        .build();

    return mailgunMessagesApi.sendMessage(YOUR_DOMAIN_NAME, message);
}
# 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";

$params =  array(
    'from'       => 'Excited User <YOU@YOUR_DOMAIN_NAME>',
    'to'         => 'foo@example.com',
    'subject'    => 'Hello',
    'text'       => 'Testing some Mailgun awesomness!',
    'o:tracking' => false
);

# Make the call to the client.
$result = $mgClient->messages()->send($domain, $params);
def send_message_no_tracking():
    return requests.post(
        "https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/messages",
        auth=("api", "YOUR_API_KEY"),
        data={"from": "Excited User <YOU@YOUR_DOMAIN_NAME>",
              "to": ["bar@example.com", "baz@example.com"],
              "subject": "Hello",
              "text": "Testing some Mailgun awesomness!",
              "o:tracking": False})
def send_message_no_tracking
  RestClient.post "https://api:YOUR_API_KEY"\
  "@api.mailgun.net/v3/YOUR_DOMAIN_NAME/messages",
  :from => "Excited User <YOU@YOUR_DOMAIN_NAME>",
  :to => "bar@example.com, baz@example.com",
  :subject => "Hello",
  :text => "Testing some Mailgun awesomness!",
  "o:tracking" => false
end
using System;
using System.IO;
using RestSharp;
using RestSharp.Authenticators;

public class SendMessageNoTrackingChunk
{

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

    public static IRestResponse SendMessageNoTracking ()
    {
        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}/messages";
        request.AddParameter ("from", "Excited User <YOU@YOUR_DOMAIN_NAME>");
        request.AddParameter ("to", "bar@example.com");
        request.AddParameter ("to", "baz@example.com");
        request.AddParameter ("subject", "Hello");
        request.AddParameter ("text", "Testing some Mailgun awesomness!");
        request.AddParameter ("o:tracking", false);
        request.Method = Method.POST;
        return client.Execute (request);
    }

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

func SendMessageNoTracking(domain, apiKey string) (string, error) {
    mg := mailgun.NewMailgun(domain, apiKey)
    m := mg.NewMessage(
        "Excited User <YOU@YOUR_DOMAIN_NAME>",
        "Hello",
        "Testing some Mailgun awesomeness!",
        "foo@example.com",
    )
    m.SetTracking(false)

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

    _, id, err := mg.Send(ctx, m)
    return id, err
}
const API_KEY = 'YOUR_API_KEY';
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: API_KEY});

const messageData = {
  from: 'Excited User <me@samples.mailgun.org>',
  to: 'alice@example.com',
  subject: 'Hello',
  text: 'Testing some Mailgun awesomeness!',
  'o:tracking': 'False'
};

client.messages.create(YOUR_DOMAIN_NAME, messageData)
.then((res) => {
  console.log(res);
})
.catch((err) => {
  console.error(err);
});

An example of how to set message delivery time using the o:deliverytime option:

curl -s --user 'api:YOUR_API_KEY' \
    https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/messages \
    -F from='Sender Bob <sbob@YOUR_DOMAIN_NAME>' \
    -F to='alice@example.com' \
    -F subject='Hello' \
    -F text='Testing some Mailgun awesomness!' \
    -F o:deliverytime='Fri, 14 Oct 2011 23:10:10 -0000'
import com.mailgun.api.v3.MailgunMessagesApi;
import com.mailgun.model.message.Message;
import com.mailgun.model.message.MessageResponse;

import java.time.ZonedDateTime;

// ...

public MessageResponse sendScheduledMessage() {
    MailgunMessagesApi mailgunMessagesApi = MailgunClient.config(API_KEY)
        .createApi(MailgunMessagesApi.class);

    Message message = Message.builder()
        .from("Excited User <USER@YOURDOMAIN.COM>")
        .to("bruce@example.com")
        .subject("Hello")
        .text("Testing out some Mailgun awesomeness!")
        .deliveryTime(ZonedDateTime.now().plusHours(2L)) // Two hours delay.
        .build();

    return mailgunMessagesApi.sendMessage(YOUR_DOMAIN_NAME, message);
}
# 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";
$params = array(
    'from'           => 'Excited User <YOU@YOUR_DOMAIN_NAME>',
    'to'             => 'bob@example.com',
    'subject'        => 'Hello',
    'text'           => 'Testing some Mailgun awesomness!',
    'o:deliverytime' => 'Wed, 01 Jan 2020 09:00:00 -0000'
);

# Make the call to the client.
$result = $mgClient->messages()->send($domain, $params);
def send_scheduled_message():
    return requests.post(
        "https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/messages",
        auth=("api", "YOUR_API_KEY"),
        data={"from": "Excited User <YOU@YOUR_DOMAIN_NAME>",
              "to": "bar@example.com",
              "subject": "Hello",
              "text": "Testing some Mailgun awesomness!",
              "o:deliverytime": "Fri, 25 Oct 2011 23:10:10 -0000"})
def send_scheduled_message
  RestClient.post "https://api:YOUR_API_KEY"\
  "@api.mailgun.net/v3/YOUR_DOMAIN_NAME/messages",
  :from => "Excited User <YOU@YOUR_DOMAIN_NAME>",
  :to => "bar@example.com",
  :subject => "Hello",
  :text => "Testing some Mailgun awesomeness!",
  "o:deliverytime" => "Fri, 25 Oct 2011 23:10:10 -0000"
end
using System;
using System.IO;
using RestSharp;
using RestSharp.Authenticators;

public class SendScheduledMessageChunk
{

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

    public static IRestResponse SendScheduledMessage ()
    {
        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}/messages";
        request.AddParameter ("from", "Excited User <YOU@YOUR_DOMAIN_NAME>");
        request.AddParameter ("to", "bar@example.com");
        request.AddParameter ("subject", "Hello");
        request.AddParameter ("text", "Testing some Mailgun awesomness!");
        request.AddParameter ("o:deliverytime",
                              "Fri, 14 Oct 2011 23:10:10 -0000");
        request.Method = Method.POST;
        return client.Execute (request);
    }

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

func SendScheduledMessage(domain, apiKey string) (string, error) {
    mg := mailgun.NewMailgun(domain, apiKey)
    m := mg.NewMessage(
        "Excited User <YOU@YOUR_DOMAIN_NAME>",
        "Hello",
        "Testing some Mailgun awesomeness!",
        "bar@example.com",
    )
    m.SetDeliveryTime(time.Now().Add(5 * time.Minute))

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

    _, id, err := mg.Send(ctx, m)
    return id, err
}
const API_KEY = 'YOUR_API_KEY';
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: API_KEY});

const messageData = {
  from: 'Excited User <me@samples.mailgun.org>',
  to: 'alice@example.com',
  subject: 'Hello',
  text: 'Testing some Mailgun awesomeness!',
  "o:deliverytime": 'Fri, 6 Jul 2017 18:10:10 -0000'
};

client.messages.create(YOUR_DOMAIN_NAME, messageData)
.then((res) => {
  console.log(res);
})
.catch((err) => {
  console.error(err);
});

An example of how to tag a message with the o:tag option:

curl -s --user 'api:YOUR_API_KEY' \
    https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/messages \
    -F from='Sender Bob <sbob@YOUR_DOMAIN_NAME>' \
    -F to='alice@example.com' \
    -F subject='Hello' \
    -F text='Testing some Mailgun awesomness!' \
    -F o:tag='September newsletter' \
    -F o:tag='newsletters'
import com.mailgun.api.v3.MailgunMessagesApi;
import com.mailgun.model.message.Message;
import com.mailgun.model.message.MessageResponse;

// ...

public MessageResponse sendTaggedMessage() {
    MailgunMessagesApi mailgunMessagesApi = MailgunClient.config(API_KEY)
        .createApi(MailgunMessagesApi.class);

    Message message = Message.builder()
        .from("Excited User <USER@YOURDOMAIN.COM>")
        .to("bruce@example.com")
        .subject("Hello")
        .text("Testing out some Mailgun awesomeness!")
        .tag("newsletters")
        .tag("September newsletter")
        .build();

    return mailgunMessagesApi.sendMessage(YOUR_DOMAIN_NAME, message);
}
# 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";
$params = array(
    'from'    => 'Excited User <YOU@YOUR_DOMAIN_NAME>',
    'to'      => 'bob@example.com',
    'subject' => 'Hello',
    'text'    => 'Testing some Mailgun awesomness!',
    'o:tag'   => array('Tag1', 'Tag2', 'Tag3')
);

# Make the call to the client.
$result = $mgClient->messages()->send($domain, $params);
def send_tagged_message():
    return requests.post(
        "https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/messages",
        auth=("api", "YOUR_API_KEY"),
        data={"from": "Excited User <YOU@YOUR_DOMAIN_NAME>",
              "to": "bar@example.com",
              "subject": "Hello",
              "text": "Testing some Mailgun awesomness!",
              "o:tag": ["September newsletter", "newsletters"]})
def send_tagged_message
  data = {}
  data[:from] = "Excited User <YOU@YOUR_DOMAIN_NAME>"
  data[:to] = "bar@example.com"
  data[:subject] = "Hello"
  data[:text] = "Testing some Mailgun awesomness!"
  data["o:tag"] = []
  data["o:tag"] << "September newsletter"
  data["o:tag"] << "newsletters"
  RestClient.post "https://api:YOUR_API_KEY"\
  "@api.mailgun.net/v3/YOUR_DOMAIN_NAME/messages", data
end
using System;
using System.IO;
using RestSharp;
using RestSharp.Authenticators;

public class SendTaggedMessageChunk
{

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

    public static IRestResponse SendTaggedMessage ()
    {
        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}/messages";
        request.AddParameter ("from", "Excited User <YOU@YOUR_DOMAIN_NAME>");
        request.AddParameter ("to", "bar@example.com");
        request.AddParameter ("subject", "Hello");
        request.AddParameter ("text", "Testing some Mailgun awesomness!");
        request.AddParameter ("o:tag", "September newsletter");
        request.AddParameter ("o:tag", "newsletters");
        request.Method = Method.POST;
        return client.Execute (request);
    }

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

func SendTaggedMessage(domain, apiKey string) (string, error) {
    mg := mailgun.NewMailgun(domain, apiKey)
    m := mg.NewMessage(
        "Excited User <YOU@YOUR_DOMAIN_NAME>",
        "Hello",
        "Testing some Mailgun awesomeness!",
        "bar@example.com",
    )

    err := m.AddTag("FooTag", "BarTag", "BlortTag")
    if err != nil {
        return "", err
    }

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

    _, id, err := mg.Send(ctx, m)
    return id, err
}
const API_KEY = 'YOUR_API_KEY';
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: API_KEY});

const messageData = {
  from: 'Excited User <me@samples.mailgun.org>',
 to: 'alice@example',
 subject: 'Tagged',
 text: 'Testing some Mailgun awesomeness!',
 "o:tag" : ['newsletters', 'September newsletter']
};

client.messages.create(YOUR_DOMAIN_NAME, messageData)
.then((res) => {
  console.log(res);
})
.catch((err) => {
  console.error(err);
});

An example of how to resend a message:

curl -s --user 'api:YOUR_API_KEY' \
    https://se.api.mailgun.net/v3/domains/YOUR_DOMAIN_NAME/messages/STORAGE_URL \
    -F to='bob@example.com'
import com.mailgun.api.v3.MailgunStoreMessagesApi;
import com.mailgun.client.MailgunClient;
import com.mailgun.model.message.MessageResponse;

// ...

public MessageResponse resendSimpleMessage() {
    MailgunStoreMessagesApi mailgunStoreMessagesApi = MailgunClient.config(STORED_MESSAGE_FULL_URL, API_KEY)
            .createApiWithAbsoluteUrl(MailgunStoreMessagesApi.class);

    return mailgunStoreMessagesApi.resendMessage("user@samples.org");
}
# Currently, the PHP SDK does not support Resend Messages endpoint.
# Consider using the following php curl function.
function resend_message() {
  $ch = curl_init();

  curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
  curl_setopt($ch, CURLOPT_USERPWD, 'api:PRIVATE_API_KEY');
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

  curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
  curl_setopt($ch, CURLOPT_URL, MESSAGE_STORAGE_URL);
  curl_setopt($ch, CURLOPT_POSTFIELDS, array(
      'to'=> 'bob@example.com'
      )
  );

  $result = curl_exec($ch);
  curl_close($ch);

  return $result;
}
def resend_simple_message():
    return requests.post(
        "https://se.api.mailgun.net/v3/YOUR_DOMAIN_NAME/messages/STORAGE_URL",
        auth=("api", "YOUR_API_KEY"),
        data={"to": ["bar@example.com", "YOU@YOUR_DOMAIN_NAME"] })
def resend_simple_message
    RestClient.post "https://api:YOUR_API_KEY"\
    "@se.api.mailgun.net/v3/domains/YOUR_DOMAIN_NAME/messages/STORAGE_URL",
    :to => "bar@example.com, YOU@YOUR_DOMAIN_NAME"
end
using System;
using System.IO;
using RestSharp;
using RestSharp.Authenticators;

public class SendSimpleMessageChunk
{

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

    public static IRestResponse ResendSimpleMessage ()
    {
        RestClient client = new RestClient ();
        client.BaseUrl = new Uri ("https://se.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 = "domains/{domain}/messages/STORAGE_URL";
        request.AddParameter ("to", "bar@example.com");
        request.Method = Method.POST;
        return client.Execute (request);
    }

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

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

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

    return mg.ReSend(ctx, "STORAGE_URL", "bar@example.com")
}
import formData from 'form-data';
import Mailgun from 'mailgun.js';

const api_key = 'YOUR_API_KEY';
const DOMAIN = 'YOUR_DOMAIN_NAME';

const data = {
  to: 'bar@example.com, alice@example.com'
};

const options = {
  /*
  The domain of storage. Can be found in Sending -> logs on your dashboard.
  The needed value is the first part of storage.url
  */
  url: 'https://se.api.mailgun.net/',
  username: 'api',
  key: api_key
};

(async () => {
  try {
    const mailgun = new Mailgun(formData);
    const client = mailgun.client(options);

    /*
      The key of message in storage.
      Can be found in Sending -> logs on your dashboard
      The needed value is located in storage.key
    */
    const storageKey = 'YOUR_MESSAGE_KEY';
    const res = await client.request.postWithFD(`v3/domains/${DOMAIN}/messages/${storageKey}`, data);
    console.log(res);
  } catch (error) {
    console.error(error);
  }
})();

An example of how to decode Quoted-printable encoded messages:

# with utility from `quoted-printable` nodejs lib (`npm install -g quoted-printable`)
decoded_message=$(quoted-printable --decode <<< "${encoded_message}")
// using Apache Commons / commons-codec
import org.apache.commons.codec.net.QuotedPrintableCodec;

// ...
String decodedMessage = new QuotedPrintableCodec().decode(encodedMessage);
$decoded_message = quoted_printable_decode($encoded_message);
import quopri

# ...
decoded_message = quopri.decodestring(encoded_message)
decoded_message = encoded_message.unpack('M*')
using System;
using System.Text.RegularExpressions;

public class DecodeMessageSample
{
    // from <http://www.dpit.co.uk/decoding-quoted-printable-email-in-c/>
    private string DecodeQuotedPrintable(string input)
    {
      var occurences = new Regex(@"(=[0-9A-Z][0-9A-Z])+", RegexOptions.Multiline);
      var matches = occurences.Matches(input);
      foreach (Match m in matches)
      {
        byte[] bytes = new byte[m.Value.Length / 3];
        for (int i = 0; i < bytes.Length; i++)
        {
           string hex = m.Value.Substring(i * 3 + 1, 2);
           int iHex = Convert.ToInt32(hex, 16);
           bytes[i] = Convert.ToByte(iHex);
         }
         input = input.Replace(m.Value, Encoding.Default.GetString(bytes));
       }
       return input.Replace("=rn", "");
    }

    public void doThings()
    {
            // ...
        var decodedMessage = DecodeQuotedPrintable(encodedMessage);
    }
}
import (
   "io/ioutil"
   "mime/quotedprintable"
   "strings"
)

func DecodeMessage(encodedMessage string) (string) {
   decodedMessage, err := ioutil.ReadAll(quotedPrintable.NewReader(strings.NewReader(encodedMessage)))
   if err != nil {
       panic(err);
   }
   return decodedMessage
}
// npm install quoted-printable
// npm install utf8
import quotedPrintable from 'quoted-printable';

const res = utf8.decode(quotedPrintable.decode('foo=3Dbar'));
console.log('result:', res);

Error codes

This is a list of possible return codes and messages from the /messages and /messages.mime endpoints.

Code Error message
400 from parameter is missing
400 to parameter is missing
400 message parameter is missing
400 ‘message’ parameter is not a file
400 Need at least one of ‘text’ or ‘html’ parameters specified
400 Only one parameters ‘html’ or ‘template’ is allowed
400 Send options (parameters starting with o:, h:, or v:) are limited to 16 kB total
400 Too many recipients, max is 1000
400 Header name must be pure ASCII: <header-name>
400 <invalid-date> is not an RFC-2822 compliant date
400 to parameter is not a valid address. please check documentation
400 Invalid request content type. Expecting ‘multipart/form-data’ but got ‘application/x-www-form-urlencoded’
400 malformed multipart/form-data request
400 unable to parse request: invalid URL escape
400 unable to parse request: unexpected EOF
400 <time> invalid 24 hour time(value of ‘o:time-zone-localize’)
400 <time> is not a valid time to send (value of ‘o:time-zone-localize’)
400 invalid delivery time format
400 to parameter is not a valid address. please check documentation
400 from parameter is not a valid address. please check documentation
400 cc parameter is not a valid address. please check documentation
400 bcc parameter is not a valid address. please check documentation
400 ‘recipient-variables’ parameter is not a valid JSON
400 Domain example.com is not allowed to send: Sandbox subdomains are for test purposes only. Please add your own domain or add the address to authorized recipients in Account Settings.
400 Domain example.com is not allowed to send: Free accounts are for test purposes only. Please upgrade or add the address to authorized recipients in Account Settings.
400 Domain example.com is not allowed to send: The domain is unverified and requires DNS configuration. Log in to your control panel to view required DNS records.
400 Domain example.com is not allowed to send: Please activate your Mailgun account. Check your inbox or log in to your control panel to resend the activation email.
400 is not a valid secondary dkim domain name
401 Forbidden
404 Domain not found: example.com
403 Domain example is not allowed to send large batches yet
403 Rejected: IP <id-address> can’t be used to send the message
413 request size exceeds 52.4MiB limit
429 Domain example.com is not allowed to send: request limit exceeded, try again after Mon, 20 Dec 2021 20:33:21 UTC
429 Domain example.com is not allowed to send: bytes limit exceeded, try again after Mon, 20 Dec 2021 20:33:21 UTC
429 Domain example.com is not allowed to send: recipient limit exceeded, try again after Mon, 20 Dec 2021 20:33:21 UTC
500 Internal Server Error

Rate Limits

429 Rate limit code messages include the reason why the request was limited and when to try again. The Message contains “why” the request was rate limited, <why> limit exceeded, try again where <why> could be one of the following.

  • request - The account was rate limited because we received too many HTTP requests.
  • recipient - The account was rate limited because we received too many email recipients in a short period of time.
  • bytes - The account was rate limited because we received too many bytes. (usually due to large attachments or very large emails)