Coder Social home page Coder Social logo

mailgun.js's Introduction

Mailgun.js

A javascript sdk for Mailgun built with webpack, babel & es6. This can be used in node or in the browser*.

NOTE: If used in the browser, a proxy is required to communicate with the Mailgun api due to cors limitations. Also, do not publish your private api key in frontend code.

Table of Contents

Documentation

Mailgun API Documentation:

Install

  • Requires node.js >= 12.x

Install mailgun.js with:

npm install mailgun.js

Setup Client

Next, require the module and instantiate a mailgun client by calling new Mailgun(formData) and then using mailgun.client setup the client with basic auth credentials (username: 'api', key: 'key-yourkeyhere').

NOTE: starting from version 3.0 you need to pass FormData (we need this to keep library universal). For node.js you can use form-data library.

Imports

Once the package is installed, you can import the library using import or require approach:

  const formData = require('form-data');
  const Mailgun = require('mailgun.js');
  const mailgun = new Mailgun(formData);
  const mg = mailgun.client({username: 'api', key: process.env.MAILGUN_API_KEY || 'key-yourkeyhere'});
  import * as FormData from 'form-data';
  import Mailgun from 'mailgun.js';
  const mailgun = new Mailgun(FormData);
  const mg = mailgun.client({username: 'api', key: process.env.MAILGUN_API_KEY || 'key-yourkeyhere'});

Types imports

Starting from version 9.0.0. Types can be includes as named import:

 import Mailgun, { MailgunClientOptions, MessagesSendResult } from 'mailgun.js';

Interfaces and Enums imports

Starting from version 9.0.0. Interfaces and Enums can be imported in the next way:

  import Mailgun, { Interfaces, Enums } from 'mailgun.js';
  ...
  const mailgunClient: Interfaces.IMailgunClient = mailgun.client(clientOptions);
  const yes = Enums.YesNo.YES;
  ...

Generated docs

The list of all available Types, Interfaces and Enums is auto-generated and located in the docs folder.

Methods

The following service methods are available to instantiated clients. The examples assume you have already created a mailgun client as mg with valid credentials.

Method naming conventions:

  • get or get{{Item}} - expected response for client is a single object
  • list or list{{Items}} - expected response for client is a list of objects
  • create or create{{Item}} - expected response for client is a single object
  • update or update{{Item}} - expected response is an object with a status message
  • destroy or destroy{{Item}} - expected response is an object with a status message

Messages

  • create

    mg.messages.create(domain, data) - api docs

    Options:

    Parameter Description
    to Email address of the recipient(s). Example: "Bob [email protected]". You can use commas to separate multiple recipients (e.g.: "[email protected],[email protected]" or ["[email protected]", "[email protected]"]).
    cc Same as To but for carbon copy
    bcc Same as To but for blind carbon copy
    subject Subject of the message.
    html HTML version of the message.
    text Text version of the message.
    message MIME string of the message. Make sure to use multipart/form-data to send this as a file upload.
    attachment File attachment. You can post multiple attachment values. Important: You must use multipart/form-data encoding when sending attachments. Also you can use {data: file, filename: filename} to define custom filename.
    o:tag Tag string. See Tagging for more information.
    o:campaign Id of the campaign the message belongs to. See um-campaign-analytics for details.
    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, no or htmlonly.
    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.
    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.
    • HTML/TEXT Example:

      mg.messages.create('sandbox-123.mailgun.org', {
          from: "Excited User <[email protected]>",
          to: ["[email protected]"],
          subject: "Hello",
          text: "Testing some Mailgun awesomness!",
          html: "<h1>Testing some Mailgun awesomness!</h1>"
        })
        .then(msg => console.log(msg)) // logs response data
        .catch(err => console.error(err)); // logs any error
    • MIME Example:

      mg.messages.create('sandbox-123.mailgun.org', {
          from: "Excited User <[email protected]>",
          to: ["[email protected]"],
          subject: "Hello",
          message: "<mime encoded string here>"
        })
        .then(msg => console.log(msg)) // logs response data
        .catch(err => console.error(err)); // logs any error
    • Messages with attachments:

      • Node.js example of send file as an attachment

          const fsPromises = require('fs').promises;
          const path = require('path');
          const filepath = path.resolve(__dirname, '../test.pdf');
          let messageParams = {
              from: "Excited User <[email protected]>",
              to: ["[email protected]"],
              subject: "Test subject",
              text: "Hello here is a file in the attachment"
          }
        
          fsPromises.readFile(filepath)
          .then(data => {
            const file = {
                filename: 'test-rename.pdf',
                data
            }
            messageParams.attachment = file;
            return mg.messages.create('sandbox-123.mailgun.org', messageParams);
          })
          .then(response => {
              console.log(response);
          })
      • Node.js example of send multiple files as an attachment

        const fsPromises = require('fs').promises;
        const path = require('path');
        const filepath = path.resolve(__dirname, '../test.pdf');
        const filepath1 = path.resolve(__dirname, '../test.jpg');
        
        let messageParams = {
            from: "Excited User <[email protected]>",
            to: ["[email protected]"],
            subject: "Test subject",
            text: "Test message"
        }
        
        (async () =>{
            try {
                const firstFile = {
                    filename: 'test.pdf',
                    data: await fsPromises.readFile(filepath)
                }
        
                const secondFile = {
                    filename: 'test.jpg',
                    data: await fsPromises.readFile(filepath1)
                }
        
                messageParams.attachment = [firstFile, secondFile];
                const result =  await mg.messages.create('sandbox-123.mailgun.org', messageParams);
                console.log(result);
                } catch (error) {
                    console.error(error);
                }
        })()
      • Node.js example of send file as inline image

          const fsPromises = require('fs').promises;
          const path = require('path');
          const filepath = path.resolve(__dirname, '../test.jpg');
          let messageParams = {
              from: "Excited User <[email protected]>",
              to: ["[email protected]"],
              subject: "Test subject",
              html: '<div><img alt="image" id="1" src="cid:test.jpg"/></div> Some extra text'
          }
        
          fsPromises.readFile(filepath)
          .then(data => {
            const file = {
                filename: 'test.jpg',
                data
            }
        
            messageParams.inline = file;
            return mg.messages.create('sandbox-123.mailgun.org', messageParams);
          })
          .then(response => console.log(response))
      • Browser example of send file

        Before sending the file you need to somehow get the Blob of the file. Usually can get it from the onChange event of input tag with type file.

        const handleFileSelected = async (event) => {
          const files = Array.from(event.target.files)
          const fileBuffer = await files[0];
        }
        <input type="file" onChange={handleFileSelected} name="file-uploader"/>

        Then you can use the same approach as shown above for node.js apps.

          const file = {
            filename: 'test.pdf',
            data: fileBuffer
          };
        
          let messageParams = {
            from: "Excited User <[email protected]>",
            to: ["[email protected]"],
            subject: "Test subject",
            text: "Hello here is a file in the attachment",
            attachment: file
          };
        
          const res = await mg.messages.create(DOMAIN, messageParams);

    Promise returns:

    {
      id: '<[email protected]>',
      message: 'Queued. Thank you.'
    }

Templates

Mailgun’s templates uses a fork of the very popular template engine handlebars.

To provide values for a substitution you need to use 'h:X-Mailgun-Variables' property in the message description.

Make sure that this property is a JSON string like:

JSON.stringify({
  "title": "A title",
  "body": "The body"
})

You can find few examples of how to use templates below.

  • Providing values for title and slug variables to render in template

      ...
      const {
        title,
        slug,
      } = someDataSource;
    
      const mailgunData = {
        from: '[email protected]>',
        to: '[email protected]',
        subject: `Email ${title}`,
        template: 'name-of-the-template-you-made-in-mailgun-web-portal',
        'h:X-Mailgun-Variables': JSON.stringify({ // be sure to stringify your payload
          title,
          slug,
        }),
        'h:Reply-To': '[email protected]',
      };
    
      try {
        const response = await mailgun.messages.create(DOMAIN_NAME, mailgunData);
      ...
  • Providing an array of objects to render them in the template

      ...
      const mailgunData = {
        from: '[email protected]>',
        to: '[email protected]',
        subject: `Email ${title}`,
        template: 'name-of-the-another-template-you-made-in-mailgun-web-portal',
        'h:X-Mailgun-Variables': JSON.stringify({
        "arrayItems": [
            {
                "question": "test_question",
                "answer": "test_answer"
            },
            {
                "question": "test_question",
                "answer": "test_answer"
            }
        ]})
      };
      try {
        const response = await mailgun.messages.create(DOMAIN_NAME, mailgunData);
      ...

Recipient Variables

Docs

Recipient Variables are custom variables that you define, which you can then reference in the message body. They give you the ability to send a custom message to each recipient while still using a single API Call.

...
const mailgunData = {
    from: 'Example.com Mailer <[email protected]>',
    to: ['[email protected]', '[email protected]'],
    subject: 'Recipient - %recipient.title%',
    html: 'Here\'s %recipient.title% and <a href="%recipient.link%">link</a>',
    'recipient-variables': JSON.stringify({
      '[email protected]': {
        title: 'Me',
        link: 'href-var',
      },
      '[email protected]': {
        title: 'You',
        link: 'slug-recipient-var-c',
      },
    }),
  };

  try {
    const response = await mailgun.messages.create(DOMAIN_NAME, mailgunData);
...

Domains

  • list

    mg.domains.list(query) - api docs

    Example:

    mg.domains.list()
      .then(domains => console.log(domains)) // logs array of domains
      .catch(err => console.error(err)); // logs any error

    Promise returns: array of Domain instances

    [{
      created_at: 'Sun, 19 Oct 2014 18:49:36 GMT',
      name: 'testing.example.com',
      receiving_dns_records: null,
      require_tls: true,
      sending_dns_records: null,
      skip_verification: true,
      smtp_login: '[email protected]',
      smtp_password: 'password',
      spam_action: 'disabled',
      state: 'unverified',
      type: 'custom',
      wildcard: true
    }]

    Query data may have next properties:

    Property Description
    limit Maximum number of records to return. (100 by default)
    skip Number of records to skip. (0 by default)
  • get

    mg.domains.get(domain)

    Example:

    mg.domains.get('testing.example.com')
      .then(domains => console.log(domains)) // logs domain object
      .catch(err => console.error(err)); // logs any error

    Promise returns: Domain instance

    {
      created_at: 'Sun, 19 Oct 2014 18:49:36 GMT',
      name: 'testing.example.com',
      receiving_dns_records: [{
          "name": "testing.example.com",
          "record_type": "TXT",
          "valid": "unknown",
          "value": "v=spf1 include:mailgun.org ~all"
        },
        {
          "name": "k1._domainkey.testing.example.com",
          "record_type": "TXT",
          "valid": "unknown",
          "value": "k=rsa; 123456"
        },
        {
          "name": "email.testing.example.com",
          "record_type": "CNAME",
          "valid": "unknown",
          "value": "mailgun.org"
        }],
      require_tls: true,
      sending_dns_records: [{
          "priority": "10",
          "record_type": "MX",
          "valid": "unknown",
          "value": "mxa.mailgun.org"
        },
        {
          "priority": "10",
          "record_type": "MX",
          "valid": "unknown",
          "value": "mxb.mailgun.org"
        }],
      skip_verification: true,
      smtp_login: '[email protected]',
      smtp_password: 'password',
      spam_action: 'disabled',
      state: 'unverified',
      type: 'custom',
      wildcard: true,
      id: '64a4291ebbe4ec7e1d78bc80',
      is_disabled: false,
      web_prefix: 'email',
      web_scheme: 'http'
    }
  • create

    mg.domains.create(data)

    Example:

    mg.domains.create({name: 'foobar.example.com'})
      .then(msg => console.log(msg)) // logs response data
      .catch(err => console.error(err)); // logs any error

    Create method accepts data object with next properties:

    Parameter Description
    name Name of the domain (ex. domain.com)
    smtp_password Password for SMTP authentication
    spam_action disabled, block, or tag
    If disabled, no spam filtering will occur for inbound messages.
    If block, inbound spam messages will not be delivered.
    If tag, inbound messages will be tagged with a spam header. Spam Filter
    The default is disabled.
    wildcard Can be string 'true' or 'false' or boolean
    Determines whether the domain will accept email for sub-domains when sending messages.
    The default is false.
    force_dkim_authority Can be string 'true' or 'false' or boolean
    If set to true, the domain will be the DKIM authority for itself even if the root domain is registered on the same mailgun account
    If set to false, the domain will have the same DKIM authority as the root domain registered on the same mailgun account
    The default is false.
    dkim_key_size 1024 or 2048
    Set the length of your domain’s generated DKIM key
    The default is 1024
    ips An optional, comma-separated list of IP addresses to be assigned to this domain. If not specified, all dedicated IP addresses on the account will be assigned. If the request cannot be fulfilled (e.g. a requested IP is not assigned to the account, etc), a 400 will be returned.
    pool_id The id of the IP Pool that you wish to assign to the domain. The pool must contain at least 1 IP. (Note: IP Pools are only available on certain plans; see http://mailgun.com/pricing)
    web_scheme String with http or https
    Set your open, click and unsubscribe URLs to use http or https
    The default is http

    Promise returns:

    name: 'foobar.example.com',
    require_tls: false,
    skip_verification: false,
    state: 'unverified',
    wildcard: false,
    spam_action: 'disabled',
    created_at: 'Tue, 04 Jul 2023 14:09:18 GMT',
    smtp_password: undefined,
    smtp_login: '[email protected]',
    type: 'custom',
    receiving_dns_records: [{
        "name": "foobar.example.com",
        "record_type": "TXT",
        "valid": "unknown",
        "value": "v=spf1 include:mailgun.org ~all"
      },
      {
        "name": "k1._domainkey.foobar.example.com",
        "record_type": "TXT",
        "valid": "unknown",
        "value": "k=rsa; 123456"
      },
      {
        "name": "email.foobar.example.com",
        "record_type": "CNAME",
        "valid": "unknown",
        "value": "mailgun.org"
      }
    ],
    sending_dns_records: [{
        "priority": "10",
        "record_type": "MX",
        "valid": "unknown",
        "value": "mxa.mailgun.org"
      },
      {
        "priority": "10",
        "record_type": "MX",
        "valid": "unknown",
        "value": "mxb.mailgun.org"
    }],
    id: '64a4291ebbe4ec7e1d78bc80',
    is_disabled: false,
    web_prefix: 'email',
    web_scheme: 'http'
  • update

    mg.domains.update(domain, options)

    Example:

    mg.domains.update('foobar.example.com',{
        wildcard: 'true',
        web_scheme: 'http',
        spam_action: 'disabled',
      })
      .then(msg => console.log(msg)) // logs response data
      .catch(err => console.error(err)); // logs any error

    Update method accepts data object with next properties:

    Property Description
    spam_action Can be string with value disabled, block, or tag. If disabled, no spam filtering will occur for inbound messages. If block, inbound spam messages will not be delivered. If tag, inbound messages will be tagged with a spam header. See Spam Filter.
    web_scheme Can be string with value http or https. Set your open, click and unsubscribe URLs to use http or https. The default is http
    wildcard Can be string 'true' or 'false' or boolean. Determines whether the domain will accept email for sub-domains. The default is false.

    Promise returns:

    {
      name: 'foobar.example.com',
      require_tls: false,
      skip_verification: false,
      state: 'unverified',
      wildcard: true,
      spam_action: 'disabled',
      created_at: 'Tue, 04 Jul 2023 14:09:18 GMT',
      smtp_password: undefined,
      smtp_login: '[email protected]',
      type: 'custom',
      receiving_dns_records: [
        {
          is_active: true,
          cached: [],
          priority: '10',
          record_type: 'MX',
          valid: 'unknown',
          value: 'mxa.mailgun.org'
        },
        {
          is_active: true,
          cached: [],
          priority: '10',
          record_type: 'MX',
          valid: 'unknown',
          value: 'mxb.mailgun.org'
        }
      ],
      sending_dns_records: [
        {
          is_active: true,
          cached: [],
          name: 'foobar.example.com',
          record_type: 'TXT',
          valid: 'unknown',
          value: 'v=spf1 include:mailgun.org ~all'
        },
        {
          is_active: true,
          cached: [],
          name: 'email.foobar.example.com',
          record_type: 'CNAME',
          valid: 'unknown',
          value: 'mailgun.org'
        }
      ],
      id: '64a5880eere4eg7e1d85bc69',
      is_disabled: false,
      web_prefix: 'email',
      web_scheme: 'http'
    }
  • destroy

    mg.domains.destroy(domainAddress)

    Example:

    mg.domains.destroy('foobar.example.com')
      .then(msg => console.log(msg)) // logs response data
      .catch(err => console.error(err)); // logs any error

    Promise returns:

    {
      message: "Domain has been deleted"
    }
  • getTracking

    mg.domains.getTracking(domainAddress)

    Example:

    mg.domains.getTracking('foobar.example.com')
      .then(msg => console.log(msg)) // logs response data
      .catch(err => console.error(err)); // logs any error

    Promise returns:

    {
      "click": {
        "active": false
      },
      "open": {
        "active": false
      },
      "unsubscribe": {
        "active": false,
        "html_footer": "\n<br>\n<p><a href=\"%unsubscribe_url%\">unsubscribe</a></p>\n",
        "text_footer": "\n\nTo unsubscribe click: <%unsubscribe_url%>\n\n"
      }
    }
  • updateTracking

    mg.domains.updateTracking(domain, trackingType, data)

    • Open Tracking Example:

      mg.domains.updateTracking('foobar.example.com', 'open', {active: true})
        .then(msg => console.log(msg)) // logs response data
        .catch(err => console.error(err)); // logs any error

      Open tracking data object properties:

      Property Description
      active Boolean, enables or disables open tracking

      Promise returns:

      {
        message: 'Tracking settings have been updated',
        open: {
          active: true
        }
      }
    • Click Tracking Example:

      mg.domains.updateTracking('foobar.example.com', 'click', {active: true})
        .then(msg => console.log(msg)) // logs response data
        .catch(err => console.error(err)); // logs any error

      Click tracking data object properties:

      Property Description
      active Boolean, enables or disables click tracking

      Promise returns:

      {
        message: 'Tracking settings have been updated',
        click: {
          active: true
        }
      }
    • Unsubscribe Tracking Example:

      mg.domains.updateTracking('foobar.example.com', 'unsubscribe', {
          active: true,
          html_footer: "\n<br>\n<p><a href=\"%unsubscribe_url%\">unsubscribe</a></p>\n",
          text_footer: "\n\nTo unsubscribe click: <%unsubscribe_url%>\n\n"
        })
        .then(msg => console.log(msg)) // logs response data
        .catch(err => console.error(err)); // logs any error

      Unsubscribe Tracking data object properties:

      Property Description
      active Boolean, enables or disables unsubscribe tracking
      html_footer string appended to html emails for managing unsubscribe links
      text_footer string appended to html emails for managing unsubscribe links

      Promise returns:

      {
        message: 'Tracking settings have been updated',
        "unsubscribe": {
          "active": true,
          "html_footer": "\n<br>\n<p><a href=\"%unsubscribe_url%\">unsubscribe</a></p>\n",
          "text_footer": "\n\nTo unsubscribe click: <%unsubscribe_url%>\n\n"
        }
      }
  • getIps

    mg.domains.getIps(domain)

    Example:

    mg.domains.getIps('foobar.example.com')
      .then(msg => console.log(msg)) // logs response data
      .catch(err => console.error(err)); // logs any error

    Promise returns:

    ["192.168.0.1", "192.168.0.2"]
  • assignIp

    mg.domains.assignIp(domain, ip)

    Example:

    mg.domains.assignIp('foobar.example.com', "192.168.0.3")
      .then(msg => console.log(msg)) // logs response data
      .catch(err => console.error(err)); // logs any error
    {
      message: 'success',
      status: 200,
    }
  • deleteIp

    mg.domains.deleteIp(domain, ip)

    Example:

    mg.domains.deleteIp('foobar.example.com', "192.168.0.3")
      .then(msg => console.log(msg)) // logs response data
      .catch(err => console.error(err)); // logs any error
    {
      message: 'success'
    }

Events

  • get

    mg.events.get(domain, data)

    Example:

    mg.events.get('foobar.example.com', {
        page: 'mypageid',
        event: 'opened'
    }).then(data => console.log(data.items)) // logs array of event objects
      .catch(err => console.error(err)); // logs any error

    Options:

    Parameter Description
    page Fetches the specified page of log records, assuming that the URL was returned by the previous request
    begin The beginning of the search time range. It can be specified as a string (see Date Format) or linux epoch seconds. Refer to Time Range for details.
    end The end of the search time range. It can be specified as a string (see Date Format) or linux epoch seconds. Refer to Time Range for details.
    ascending Defines the direction of the search time range if the range end time is not specified. Can be either yes or no. Refer to Time Range for details.
    limit Number of entries to return. (300 max)
    field field is the name of the Filter Field. The value of the parameter should be a valid Filter Expression. Several field filters can be specified in one request. If the same field is mentioned, more then once, then all its filter expressions are combined with AND operator.
    • Example with Date and Filter field

        const date = new Date(2023, 7, 2, 0, 0, 0, 0); // Wed Aug 02 2023 00:00:00 GMT+0300
          const events = await mg.events.get('foobar.example.com', {
            begin: date.toUTCString(), // 'Tue, 01 Aug 2023 21:00:00 GMT'
            ascending: 'yes',
            limit: 5,
            event: 'delivered'
          });

    Promise returns: items (array of event objects), pages (paging keys grouped by id)

    {
    items: [{
        type: 'accepted',
        summary: 'got it',
        content: { more: 'data' },
        timestamp: Wed Nov 19 2014 10:32:57 GMT-0800 (PST) },
      }],
      pages: {
        first: { id: 'first', number: 'W3siYSI6IGZhbHNlLC', url: 'apiurl' },
        last: { id: 'last', number: 'W3siYSI6IGZhbHNlLC', url: 'apiurl' },
        next: { id: 'next', number: W3siYSI6IGZhbHNlLC'', url: 'apiurl' },
        previous: { id: 'previous', number: 'W3siYSI6IGZhbHNlLC', url: 'apiurl' }
      }
    }

Stats

  • Stats Options

    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 resolution encoded. If provided, overwrites the start date. See list below.

    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

    Examples:

    • 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

    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 mailgun.org.
    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 mailgun.org.
    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
  • getDomain

    mg.stats.getDomain(domain, query)

    Example:

    mg.stats.getDomain('foobar.example.com', {event: ['delivered', 'accepted', 'failed', 'complained']})
      .then(msg => console.log(msg)) // logs response data
      .catch(err => console.error(err)); // logs any error

    Promise returns:

    {
      start: Sun Mar 15 2015 17:00:00 GMT-0700 (PDT),
      end: Sun Mar 22 2015 17:00:00 GMT-0700 (PDT),
      resolution: 'day',
      stats: [{
        time: Sun Mar 15 2015 17:00:00 GMT-0700 (PDT),
        delivered: { smtp: 2, http: 1, total: 3 }
      }]
    }
  • getAccount

    mg.stats.getDomain(domain, query)

    Example:

    mg.stats.getDomain('foobar.example.com', {event: ['delivered', 'accepted', 'failed', 'complained']})
      .then(msg => console.log(msg)) // logs response data
      .catch(err => console.error(err)); // logs any error

    Promise returns:

    {
      start: Sun Mar 15 2015 17:00:00 GMT-0700 (PDT),
      end: Sun Mar 22 2015 17:00:00 GMT-0700 (PDT),
      resolution: 'day',
      stats: [{
        time: Sun Mar 15 2015 17:00:00 GMT-0700 (PDT),
        delivered: { smtp: 2, http: 1, total: 3 }
      }]
    }

Suppressions

  • list

    mg.suppressions.list(domain, suppressionType, query?)

    • Bounces Example:

      mg.suppressions.list('foobar.example.com', 'bounces')
        .then(msg => console.log(msg)) // logs response data
        .catch(err => console.error(err)); // logs any error
    • Unsubscribes Example:

      mg.suppressions.list('foobar.example.com', 'unsubscribes')
        .then(msg => console.log(msg)) // logs response data
        .catch(err => console.error(err)); // logs any error
    • Complaints Example:

      mg.suppressions.list('foobar.example.com', 'complaints')
        .then(msg => console.log(msg)) // logs response data
        .catch(err => console.error(err)); // logs any error

      Promise returns:

      {
      items: [
        {
          type: "bounces",
          address: "[email protected]",
          code: 550,
          error: "No such mailbox",
          created_at: Fri Oct 21 2011 04:02:55 GMT-0700 (PDT)
        }],
      pages: {
        first: { id: "first", page: "", address: "", url: "apiurl" },
        last: { id: "last", page: "", address: "", url: "apiurl" },
        next: { id: "next", page: "", address: "", url: "apiurl" },
        previous: { id: "prev", page: "", address: "", url: "apiurl" }
      }
      }
  • get

    mg.suppressions.get(domain, suppressionType, address)

    • Bounces Example:

      mg.suppressions.get('foobar.example.com', 'bounces', '[email protected]')
        .then(msg => console.log(msg)) // logs response data
        .catch(err => console.error(err)); // logs any error
    • Unsubscribes Example:

      mg.suppressions.get('foobar.example.com', 'unsubscribes', '[email protected]')
        .then(msg => console.log(msg)) // logs response data
        .catch(err => console.error(err)); // logs any error
    • Complaints Example:

      mg.suppressions.get('foobar.example.com', 'complaints', '[email protected]')
        .then(msg => console.log(msg)) // logs response data
        .catch(err => console.error(err)); // logs any error

    Response example:

    {
      type: "bounces",
      address: "[email protected]",
      tags: [ "*" ],
      created_at: Fri Oct 21 2011 05:02:55 GMT-0700 (PDT)
    }
  • create

    mg.suppressions.create(domain, suppressionType, data || data[])

    • Bounces Example:

      mg.suppressions.create('foobar.example.com', 'bounces', [{address: '[email protected]'}])
        .then(msg => console.log(msg)) // logs response data
        .catch(err => console.error(err)); // logs any error

      Bounces Options: Contains an array with the following object properties

      Parameter Description
      address Valid email address
      code Error code (optional, default: 550)
      error Error description (optional, default: empty string)
      created_at Timestamp of a bounce event in RFC2822 format (optional, default: current time)

      Promise returns:

      {
        message: "1 address has been added to the bounces table"
      }
    • Unsubscribes Example:

      mg.suppressions.create('foobar.example.com', 'unsubscribes', {address: '[email protected]'})
        .then(msg => console.log(msg)) // logs response data
        .catch(err => console.error(err)); // logs any error

      Unsubscribes Options: Contains an array with the following object properties

      Parameter Description
      address Valid email address
      tag Tag to unsubscribe from, use * to unsubscribe an address from all domain’s correspondence (optional, default: *)
      tags Array with tags to unsubscribe from
      created_at Timestamp of a bounce event in RFC2822 format (optional, default: current time)

      Promise returns:

      {
        message: "1 address has been added to the unsubscribes table"
      }
      • Unsubscribe from one tag

        mg.suppressions.create('foobar.example.com', 'unsubscribes', {address: '[email protected]', tag: 'your_tag_to_unsubscribe']})
          .then(msg => console.log(msg)) // logs response data
          .catch(err => console.error(err)); // logs any error

        Promise returns:

        {
          message: "1 address has been added to the unsubscribes table"
        }
      • Unsubscribe from particular tags

        mg.suppressions.create('foobar.example.com', 'unsubscribes', [{address: '[email protected]', tags: ['your_tag_to_unsubscribe', 'another_tag_to_unsubscribe']}])
          .then(msg => console.log(msg)) // logs response data
          .catch(err => console.error(err)); // logs any error

        Promise returns:

        {
          message: "1 address has been added to the unsubscribes table"
        }
    • Complaints Example:

      mg.suppressions.create('foobar.example.com', 'complaints', [{address: '[email protected]'}])
        .then(msg => console.log(msg)) // logs response data
        .catch(err => console.error(err)); // logs any error

      Complaints Options: Contains an array with the following object properties

      Parameter Description
      address Valid email address
      created_at Timestamp of a bounce event in RFC2822 format (optional, default: current time)

      Promise returns:

      {
        message: "1 address has been added to the complaints table"
      }
  • destroy

    mg.suppressions.destroy(domain, suppressionType, address)

    • Bounces Example:

      mg.suppressions.destroy('foobar.example.com', 'bounces', '[email protected]')
        .then(msg => console.log(msg)) // logs response data
        .catch(err => console.error(err)); // logs any error

      Promise returns:

      {
        message: "Bounced address has been removed",
        value: "",
        address: "[email protected]",
        status: 200
      }
    • Unsubscribes Example:

      mg.suppressions.destroy('foobar.example.com', 'unsubscribes', '[email protected]')
        .then(msg => console.log(msg)) // logs response data
        .catch(err => console.error(err)); // logs any error

      Promise returns:

      {
        message: 'Unsubscribe event has been removed',
        value: '',
        address: '[email protected]',
        status: 200
      }
    • Complaints Example:

      mg.suppressions.destroy('foobar.example.com', 'complaints', '[email protected]')
        .then(msg => console.log(msg)) // logs response data
        .catch(err => console.error(err)); // logs any error

      Promise returns:

        message: 'Spam complaint has been removed',
        value: '',
        address: 'bob@example.com',
        status: 200

Webhooks

  • list

    mg.webhooks.list(domain, query)

    Example:

    mg.webhooks.list('foobar.example.com')
      .then(msg => console.log(msg)) // logs response data
      .catch(err => console.error(err)); // logs any error

    Promise returns:

    {
      open: { 'url': 'http://requestb.in' },
      click: { 'url': 'http://requestb.in' },
      bounce: { 'url': 'http://requestb.in' },
      deliver: { 'url': 'http://requestb.in' },
      drop: { 'url': 'http://requestb.in' },
      spam: { 'url': 'http://requestb.in' },
      unsubscribe: { 'url': 'http://requestb.in' },
      click: { 'url': 'http://requestb.in' },
      open: { 'url': 'http://requestb.in' },
    }
  • get

    mg.webhooks.get(domain, id)

    Example:

    mg.webhooks.get('foobar.example.com', 'open') // bounce, deliver, drop, spam, unsubscribe, click, open
      .then(msg => console.log(msg)) // logs response data
      .catch(err => console.error(err)); // logs any error

    Promise returns:

    {
      'open': { 'url': 'http://requestb.in', 'urls': ['trackclick.com'] }
    }
  • create

    mg.webhooks.create(domain, id, data, test)

    Example:

    mg.webhooks.create('foobar.example.com', 'open', 'http://requestb.in') // bounce, deliver, drop, spam, unsubscribe, click, open
      .then(msg => console.log(msg)) // logs response data
      .catch(err => console.error(err)); // logs any error

    Promise returns:

    {
      'open': { 'url': 'http://requestb.in', 'urls': ['http://requestb.in'] }
    }

    Test Webhook Example:

    mg.webhooks.get('foobar.example.com', 'open', 'http://requestb.in', true) // bounce, deliver, drop, spam, unsubscribe, click, open
      .then(msg => console.log(msg)) // logs response data
      .catch(err => console.error(err)); // logs any error

    Promise returns:

    {
      'code': '500',
      'message': 'Hi!'
    }
  • update

    mg.webhooks.update(domain, id, url, test)

    Example:

    mg.webhooks.update('foobar.example.com', 'open', 'http://requestb.in') // bounce, deliver, drop, spam, unsubscribe, click, open
      .then(msg => console.log(msg)) // logs response data
      .catch(err => console.error(err)); // logs any error

    Promise returns:

    {
      'open': { 'url': 'http://requestb.in', 'urls': ['http://requestb.in'] }
    }
    mg.webhooks.update('foobar.example.com', 'open', ['http://requestb.in', 'http://requestb1.in' ]) // bounce, deliver, drop, spam, unsubscribe, click, open
      .then(msg => console.log(msg)) // logs response data
      .catch(err => console.error(err)); // logs any error

    Promise returns:

    {
      'open': { 'url': 'http://requestb.in', 'urls': ['http://requestb.in', 'http://requestb1.in'] }
    }
  • destroy

    mg.webhooks.destroy(domain, id)

    Example:

    mg.webhooks.update('foobar.example.com', 'open') // bounce, deliver, drop, spam, unsubscribe, click, open
      .then(msg => console.log(msg)) // logs response data
      .catch(err => console.error(err)); // logs any error

    Promise returns:

    {
      'open': { 'url': 'http://requestb.in', 'urls': ['http://requestb.in']}
    }

Routes

  • list

    mg.routes.list(query)

    Example:

    mg.routes.list()
      .then(data => console.log(data)) // logs response body
      .catch(err => console.error(err)); // logs any error

    Promise returns:

    [
      {
        actions: [ 'forward("http://myhost.com/messages/")', 'stop()' ],
        created_at: 'Mon, 26 Oct 2015 03:56:51 GMT',
        description: 'sample',
        expression: 'match_recipient(".*@example.com")',
        id: '562da483125730608a7d1719',
        priority: 0
      }
    ]
  • get

    mg.routes.get(id)

    Example:

    mg.routes.get('562da483125730608a7d1719')
      .then(data => console.log(data)) // logs response body
      .catch(err => console.error(err)); // logs any error

    Promise returns: response body

    {
      actions: [ 'forward("http://myhost.com/messages/")', 'stop()' ],
      created_at: 'Mon, 26 Oct 2015 03:56:51 GMT',
      description: 'sample',
      expression: 'match_recipient(".*@example.com")',
      id: '562da483125730608a7d1719',
      priority: 0
    }
  • create

    mg.routes.create(options)

    Example:

    mg.routes.create({
        priority: 0,
        description: 'sample',
        expression: 'match_recipient(".*@example.org")',
        action: ['forward("http://myhost.com/messages/")', 'stop()']
      })
      .then(data => console.log(data)) // logs response body
      .catch(err => console.error(err)); // logs any error

    Promise returns: response body

    {
      actions: [ 'forward("http://myhost.com/messages/")', 'stop()' ],
      created_at: 'Mon, 26 Oct 2015 03:56:51 GMT',
      description: 'sample',
      expression: 'match_recipient(".*@example.com")',
      id: '562da483125730608a7d1719',
      priority: 0
    }
  • update

    mg.routes.update(id, options)

    Example:

    mg.routes.update('562da483125730608a7d1719', {
        priority: 0,
        description: 'sample',
        expression: 'match_recipient(".*@example.org")',
        action: ['forward("http://myhost.com/messages/")', 'stop()']
      })
      .then(data => console.log(data)) // logs response body
      .catch(err => console.error(err)); // logs any error

    Promise returns: response body

    {
      actions: [ 'forward("http://myhost.com/messages/")', 'stop()' ],
      created_at: 'Mon, 26 Oct 2015 03:56:51 GMT',
      description: 'sample',
      expression: 'match_recipient(".*@example.com")',
      id: '562da483125730608a7d1719',
      message: 'Route has been updated',
      priority: 0
    }
  • destroy

    mg.routes.destroy(id)

    Example:

    mg.routes.destroy('562da483125730608a7d1719')
      .then(data => console.log(data)) // logs response body
      .catch(err => console.error(err)); // logs any error

    Promise returns: response body

    {
      id: '562da483125730608a7d1719',
      message: 'Route has been deleted'
    }

Validation

  • get

    mg.validate.get(address)

    Example:

    mg.validate.get('[email protected]')
      .then(data => console.log(data)) // logs response body
      .catch(err => console.error(err)); // logs any error

    Promise returns: response body

    {
      address: '[email protected]',
      did_you_mean: null,
      is_valid: false,
      parts: {
         display_name: null,
          domain: null,
          local_part: null
      }
    }

Multiple validation

https://documentation.mailgun.com/en/latest/api-email-validation.html#email-validation

  • create

    mg.validate.multipleValidation.create('name_of_the_list', { file })

    const fsPromises = require('fs').promises;
    const filepath = path.resolve(__dirname, '../path_to_your_file_with_emails_list.csv');
    
    ...
    
    (async () => {
      try {
        const file = {
          filename: 'test.csv',
          data: await fsPromises.readFile(filepath)
        };
    
        const validateBulkResult = await mg.validate.multipleValidation.create('name_of_the_list', { file });
        console.log('validateBulkResult', validateBulkResult);
      } catch (error) {
        console.error(error);
      }
    })();

    Response shape:

    {
      "id": "name_of_the_list",
      "message": "The validation job was submitted."
    }
  • list

    mg.validate.multipleValidation.list()

    mg.validate.multipleValidation.list()
      .then(data => console.log(data)) // logs response body
      .catch(err => console.error(err)); // logs any error

    Response shape:

    {
      "jobs": [
        {
          "created_at": 1643965937,
          "download_url": {
            "csv": "csv-url",
            "json": "json-url"
          },
          "id": "name_of_the_list",
          "quantity": 40,
          "records_processed": 40,
          "status": "uploaded",
          "summary": {
            "result": {
              "catch_all": 0,
              "deliverable": 0,
              "do_not_send": 0,
              "undeliverable": 0,
              "unknown": 40
            },
            "risk": { "high": 0, "low": 0, "medium": 0, "unknown": 40 }
          }
        }
      ],
      "paging": {
        "first": "https://api.mailgun.net/v4/address/validate/bulk?limit=100&page=first&pivot=",
        "last": "https://api.mailgun.net/v4/address/validate/bulk?limit=100&page=last&pivot=",
        "next": "https://api.mailgun.net/v4/address/validate/bulk?limit=100&page=next&pivot=b4808b5b-1111-2222-3333-6cd0b63f41ea",
        "prev": "https://api.mailgun.net/v4/address/validate/bulk?limit=100&page=prev&pivot="
      },
      "total": 1
    }
  • get

    mg.validate.multipleValidation.get('name_of_the_list')

    mg.validate.multipleValidation.get('name_of_the_list')
      .then(data => console.log(data)) // logs response body
      .catch(err => console.error(err)); // logs any error

    Response shape:

    {
      "created_at": 1643965937,
      "download_url": {
        "csv": "csv-url",
        "json": "json-url"
      },
      "id": "name_of_the_list",
      "quantity": 40,
      "records_processed": 40,
      "responseStatusCode": 200,
      "status": "uploaded",
      "summary": {
        "result": {
          "catch_all": 0,
          "deliverable": 0,
          "do_not_send": 0,
          "undeliverable": 0,
          "unknown": 40
        },
        "risk": { "high": 0, "low": 0, "medium": 0, "unknown": 40 }
      }
    }
  • destroy

    mg.validate.multipleValidation.destroy('name_of_the_list');

    cancels bulk validation job

    mg.validate.multipleValidation.destroy('name_of_the_list');
      .then(data => console.log(data)) // logs response body
      .catch(err => console.error(err)); // logs any error

    Response shape:

    {
      body: "Validation job canceled.",
      status: 200
    }

Mailing lists

A client to manage mailing lists.

  • list

    mg.lists.list()

    Example:

    mg.lists.list()
      .then(data => console.log(data)) // logs response body
      .catch(err => console.error(err)); // logs any error

    Promise returns: response body

    [
      {
        access_level: 'readonly',
        address: '[email protected]',
        created_at: 'Wed, 27 Oct 2021 21:59:21 -0000',
        description: '',
        members_count: 0,
        name: '',
        reply_preference: 'list'
      }
    ]
  • get

    mg.lists.get(mailListAddress)

    Example:

    mg.lists.get('[email protected]')
      .then(data => console.log(data)) // logs response body
      .catch(err => console.error(err)); // logs any error

    Promise returns:

    {
      access_level: 'readonly',
      address: '[email protected]',
      created_at: 'Thu, 28 Oct 2021 00:16:56 -0000',
      description: '',
      members_count: 0,
      name: '',
      reply_preference: 'list'
    }
  • create

    mg.lists.create(data)

    Example:

    mg.lists.create({
        address: '[email protected]',
        name: 'Reply Address', // optional, modifiable on website
        description: 'Mailing lists for repliable address', // optional, modifiable on website
        access_level: 'readonly', // optional, modifiable on website
        reply_preference: 'list', // optional, modifiable on website
      })
      .then(data => console.log(data)) // logs response body
      .catch(err => console.error(err)); // logs any error

    Promise returns:

    {
      access_level: 'readonly',
      address: '[email protected]',
      created_at: 'Thu, 28 Oct 2021 03:12:17 -0000',
      description: 'Mailing lists for repliable address',
      members_count: 0,
      name: 'Reply Address',
      reply_preference: 'list'
    }
  • update

    mg.lists.update(mailListAddress)

    Example:

    mg.lists.update('[email protected]', {
        address: '[email protected]',
        name: 'Foo', // optional, modifiable on website
        description: 'Foo bar bat', // optional, modifiable on website
        access_level: 'members', // optional, modifiable on website
        reply_preference: 'sender', // optional, modifiable on website
      })
      .then(data => console.log(data)) // logs response body
      .catch(err => console.error(err)); // logs any error

    Promise returns:

    {
      access_level: 'members',
      address: '[email protected]',
      created_at: 'Thu, 28 Oct 2021 03:21:15 -0000',
      description: 'Foo bar bat',
      members_count: 0,
      name: 'Foo',
      reply_preference: 'sender'
    }
  • destroy

    mg.lists.destroy(mailListAddress)

    Example:

    mg.lists.destroy('[email protected]')
      .then(data => console.log(data)) // logs response body
      .catch(err => console.error(err)); // logs any error

    Promise returns: response body

    {
      address: '[email protected]',
      message: 'Mailing list has been removed'
    }

Mailing list members

A client to manage members within a specific mailing list.

  • listMembers

    mg.lists.members.listMembers(mailListAddress)

    Example:

    mg.lists.members.listMembers('[email protected]')
      .then(data => console.log(data)) // logs response body
      .catch(err => console.error(err)); // logs any error

    Promise returns:

    [
      {
        address: '[email protected]',
        name: 'Jane Doe',
        subscribed: true,
        vars: { age: 50 }
      }
    ]
  • getMember

    mg.lists.members.getMember(mailListAddress, mailListMemberAddress)

    Example:

    mg.lists.members.getMember('[email protected]', '[email protected]')
      .then(data => console.log(data)) // logs response body
      .catch(err => console.error(err)); // logs any error

    Promise returns:

    {
      address: '[email protected]',
      name: 'Jane Doe',
      subscribed: true,
      vars: { age: 50 }
    }
  • createMember

    mg.lists.members.createMember(mailListAddress, data)

    Example:

    mg.lists.members.createMember('[email protected]', {
        address: '[email protected]',
        name: 'John Smith', // optional, modifiable on website
        vars: {hobby: "chess"}, // optional, modifiable on website
        subscribed: 'no', // optional, modifiable on website
        upsert: 'yes', // optional, choose yes to insert if not exist, or update it exist
      })
      .then(data => console.log(data)) // logs response body
      .catch(err => console.error(err)); // logs any error

    Promise returns: response body

    {
      address: '[email protected]',
      name: 'John Smith',
      subscribed: false,
      vars: { hobby: 'chess' }
    }
  • createMembers

    mg.lists.members.createMembers(mailListAddress, data)

    Example:

    mg.lists.members.createMembers('[email protected]', {
        members: [
          {
            address: "[email protected]",
            name: "Bot1 Superbot",
            vars: {location: "loc1"},
            subscribed: true,
          },
          {
            address: "[email protected]",
            name: "Bot2 Superbot",
            vars: {location: "loc2"},
            subscribed: false,
          },
        ],
        upsert: "yes",
      })
      .then(data => console.log(data)) // logs response body
      .catch(err => console.error(err)); // logs any error

    Promise returns:

    {
      list: {
        access_level: 'readonly',
        address: '[email protected]',
        created_at: 'Thu, 28 Oct 2021 03:21:15 -0000',
        description: 'For reply purpose',
        members_count: 2,
        name: 'Reply',
        reply_preference: 'list'
      },
      message: 'Mailing list has been updated',
      'task-id': '575b943c37a211ec8a520242ac11000a'
    }
  • updateMember

    mg.lists.members.updateMember(mailListAddress, mailListMemberAddress, data)

    Example:

    mg.lists.members.updateMember('[email protected]', '[email protected]', {
        address: '[email protected]',
        name: 'Bot0 Normalbot', // optional, modifiable on website
        vars: {location: "space"},
        subscribed: false,
      })
      .then(data => console.log(data)) // logs response body
      .catch(err => console.error(err)); // logs any error

    Promise returns: response body

    {
      address: '[email protected]',
      name: 'Bot0 Normalbot',
      subscribed: false,
      vars: { location: 'space' }
    }
  • destroyMember

    mg.lists.members.destroyMember(mailListAddress, mailListMemberAddress)

    Example:

    mg.lists.members.destroyMember('[email protected]', '[email protected]')
      .then(data => console.log(data)) // logs response body
      .catch(err => console.error(err)); // logs any error

    Promise returns: response body

    {
      member: { address: '[email protected]' },
      message: 'Mailing list member has been deleted'
    }

Navigation thru lists

Most of the methods that return items in a list support pagination. There are two ways to receive part of the list:

  1. Provide properties 'limit' and 'page' in the query. This way uses more frequently in the SDK and works for the next methods:
  • mg.domains.domainTags.list()

  • mg.domains.domainTemplates.list()

  • mg.domains.domainTemplates.listVersions()

  • mg.events.get()

  • mg.lists.list()

  • mg.lists.members.listMembers()

  • mg.validate.list()

  • mg.suppressions.list()

    The general idea is that after you made the first call with a limit property in the query you will receive a response with a property called pages in it. This property implements the next interface:

    {
        previous: {
            id: string;
            page: string;
            iteratorPosition: string | undefined;
            url: string
        };
        first: {
            id: string;
            page: string;
            iteratorPosition: string | undefined;
            url: string
        };
        last: {
            id: string;
            page: string;
            iteratorPosition: string | undefined;
            url: string
        };
        next: {
            id: string;
            page: string;
            iteratorPosition: string | undefined;
            url: string
        };
    }

    To receive the next page you need to add the page property to the query argument. This property should contain a string value from 'page' property in response.pages.(previous/first/last/next).

    Example:

    // first call
    const listMembers = await mg.lists.members.listMembers('your_mailing_list', { limit: 2 });
    
    /* response
    {
      items: [
        {
          address: '[email protected]',
          name: 'test name 0',
          subscribed: true,
          vars: [Object]
        },
        {
          address: '[email protected]',
          name: 'test name 1',
          subscribed: true,
          vars: [Object]
        }
      ],
      pages: {
        first: {
          id: 'first',
          page: '?page=first&limit=2',
          iteratorPosition: undefined,
          url: 'https://your_domain/v3/lists/your_mailing_list/members/pages?page=first&limit=2'
        },
        last: {
          id: 'last',
          page: '?page=last&limit=2',
          iteratorPosition: undefined,
          url: 'https://your_domain/v3/lists/your_mailing_list/members/pages?page=last&limit=2'
        },
        next: {
          id: 'next',
          page: '?page=next&address=test-1%40example.com&limit=2',
          iteratorPosition: '[email protected]',
          url: 'https://your_domain/v3/lists/your_mailing_list/members/pages?page=next&address=test-1%40example.com&limit=2'
        },
        previous: {
          id: 'previous',
          page: '?page=prev&address=test-0%40example.com&limit=2',
          iteratorPosition: '[email protected]',
          url: 'https://your_domain/v3/lists/your_mailing_list/members/pages?page=prev&address=test-0%40example.com&limit=2'
        }
      }
    }
    */
    // second call
    const listMembers = await mg.lists.members.listMembers(
        'your_mailing_list',
        {
          limit: 2,
          page: '?page=next&address=test-1%40example.com&limit=2'
        }
      );
    
    /* response
    {
      items: [
        {
          address: '[email protected]',
          name: 'test name 2',
          subscribed: true,
          vars: [Object]
        },
        {
          address: '[email protected]',
          name: 'test name 3',
          subscribed: true,
          vars: [Object]
        }
      ],
      pages: {
        first: {
          id: 'first',
          page: '?page=first&limit=2',
          iteratorPosition: undefined,
          url: 'https://your_domain/v3/lists/your_mailing_list/members/pages?page=first&limit=2'
        },
        last: {
          id: 'last',
          page: '?page=last&limit=2',
          iteratorPosition: undefined,
          url: 'https://your_domain/v3/lists/your_mailing_list/members/pages?page=last&limit=2'
        },
        next: {
          id: 'next',
          page: '?page=next&address=test-3%40example.com&limit=2',
          iteratorPosition: '[email protected]',
          url: 'https://your_domain/v3/lists/your_mailing_list/members/pages?page=next&address=test-3%40example.com&limit=2'
        },
        previous: {
          id: 'previous',
          page: '?page=prev&address=test-2%40example.com&limit=2',
          iteratorPosition: '[email protected]',
          url: 'https://your_domain/v3/lists/your_mailing_list/members/pages?page=prev&address=test-2%40example.com&limit=2'
        }
      }
    }
    */
    1. The second option of navigation is to provide properties 'limit' and 'skip' in the query. This way uses only in a few places for now:
    • mg.domains.list()
    • mg.domains.domainCredentials.list()
    • mg.routes.list()
    • mg.webhooks.list() The main idea here is quite simple you just need to provide how many records from the start of a list you want to skip and how many to receive. You can do it using the query parameter in each method. Example:
    const listDomainCredentials = await client.domains.domainCredentials.list(
    'your_domain_name',
    {
      skip: 10,
      limit: 1
    }
    );

Browser Demo

image

For this demo to work, you'll need to install and run http-proxy locally. Install it with:

npm install -g http-proxy

Then run the following command from the mailgun-js directory:

http-server -p 4001 --proxy="https://api.mailgun.net"

Demo should be up and running at http://0.0.0.0:4001/examples/

Development

Requirements

  • Requires node.js >= 4.x

Install node dependencies with:

npm install

Build

Build for dev purposes(without minimizing)

npm run build

Build for release purposes(include minimizing)

npm run build:release

Merging changes

Before PR merge check that commits info will be correctly added to the CHANGELOG.md file: 'npm run release -- --dry-run'

CI process isn't working currently, so please manually run npm run test

Tests

npm run tests

Watch tests with

npm run watch-tests

To test new functionality locally using npm link please use npm script npm run link. This is needed for correct exporting d.ts files.

Release Process

Releases occur after feature branches have been tested and merged into master.

First, checkout master and pull the latest commits.

git checkout master
git pull

Next, run npm run release.

After that, cd ./dist and then run npm login and npm publish to publish changes on npm.

mailgun.js's People

Contributors

0xflotus avatar andrii-yelis avatar charlesfries avatar dependabot[bot] avatar dsoaress avatar eddywashere avatar eyaleizenberg avatar fanchenbao avatar from-nibly avatar gorvgoyl avatar happyzombies avatar harveysanders avatar hattorius avatar highlycaffeinated avatar i-am-ebere avatar jakallergis avatar japhetholu avatar jbaranguan avatar kopertop avatar melmacaluso avatar olexandr-mazepa avatar omazepa avatar osdiab avatar popod avatar septs avatar srph avatar vigneshnin avatar zacharytyhacz avatar zeefarmer avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mailgun.js's Issues

recipient-variable nested JSON format

Say I wanted to send nested JSON as 'recipient-variables'. How would I do that, so that, I could address it in my html as %recipient.single_nested.double_nested%. I am not being able to do it at the moment.

Batch sending 1000 recipients limit

Hey everbody. Just wanted to know if this module handles the batch limit automatically (e.g. you send to 3000 recipients, and it internally makes 3 calls) or we have to manage it?
@eddywashere you seem to be the main developer, please help 😄

TypeError: Cannot read property 'indexOf' of undefined

TypeError: Cannot read property 'indexOf' of undefined
at IncomingMessage. (/var/app/current/node_modules/mailgun-js/lib/request.js:217:72)
at emitNone (events.js:91:20)
at IncomingMessage.emit (events.js:185:7)
at endReadableNT (_stream_readable.js:978:12)
at _combinedTickCallback (internal/process/next_tick.js:80:11)
at process._tickDomainCallback (internal/process/next_tick.js:128:9)

Make APIError inherit from Error

I have to add corner cases to my code and recreate exceptions because APIError does not inherit from Error. For instance, I have to do this when working with Sentry. It is generally good, common practice that when throwing an exception in Node/JS that your error class inherits from Error. A very small change that will remove annoying hacks from my codebase :)

Can I create a client only with username and password (and not key nor api_key)?

Hi all!
I've been happily working with Mailgun in several projects and it works like a charm!

Now, for the first time, I'm trying to use Mailgun with node. Historically, I've always used the Mailgun SMTP Adapter instead of the API, which only asks for my app's username and password (and hostname, server, and so on) for authentication purposes.

Is there a way to supply only those credentials, since access to keys has not (and probably won't) been provided?

Thanks!

Getting a 301 error when using mailgun-js

Hi, guys, I'm building an email verification feature, using this for my data:

{"from":"[email protected]","to":"[email protected]","subject":"Verify your email","text":"Hello,<br> Please click on the link to verify your email.<br><a href=https://mail-verification-baruchkogan.c9users.io/verify/borisbaruch kogan/Zr6expRlUhnKrXzBHg9X1gyT9laFSl1w91wrESv4B25tWnBDSphp8wKLTbeV4cFf>Click here to verify</a>"}

And calling it with this function:

mailgun.messages().send(data, function (error, body) { if(error) {console.log('mailgun error: ', error)} console.log(body); }

Which returns:

`mailgun error: { [Error:

<title>301 Moved Permanently</title>

301 Moved Permanently


nginx ] statusCode: 301 } undefined`

What am I doing wrong?

Add support to override attachment file name

Within the file and method request.js -> postMulti we could pass FormData an extra param object, { filename: } that would allow us to override the name of the file(s) attached to the email. This could be handled similar to how the Bojand/Mailgun-JS implementation handles this feature.

i.e.

formData.append(key, $file, { filename: $fileName });

An example use-case for this type of feature would be a similar scenario as noted below

A NodeJS REST API application generates a temporary file(s) need for an emails attachment(s). These files are created with random unique filename(s), basically a hash. To provide a better UX for the end user to know what the attached file(s) are, the hashed names are overridden with a more specific name(s), i.e. lzmLymzKoXZv becomes Order-Invoice.

If we could provide the desired name of the attachment file(s), the scenario above would simplify current business logic. Because the file(s) are generated by an API server, which could have multiple requests hit at once, the logic has to create a unique folder for the generated file(s) to avoid conflicting file names. After the email is sent the folder and file is then removed.

It would be much simpler logic to just remove the file that a handle already exists for in context, instead of having to target the parent folder and remove it. Which also poses it own complexity because the user could of sent another request to the API which generates another file, at which point the folder cannot be removed yet. I understand this is being nit-picky on removing the generated folder(s), but that doesn't negate the lack of a basic feature of FormData

cited sources noted above:
https://github.com/mailgun/mailgun-js/blob/master/lib/request.js#L105
https://github.com/bojand/mailgun-js/blob/master/lib/request.js#L205

lodash security vuln

mailgun relies on outdated version of lodash with high level security vulnerabilities
Screen Shot 2020-08-19 at 6 17 06 PM

library should accept URL given by Dashboard

Dashboard provides 2 data parts: API key and 'Base URL' as 'https://api.eu.mailgun.net/v3/m.domain.com'

Library should work with these 2 data parts:

let mailgun = require('mailgun.js') // DOT, not DASH, that's another library
let mailgun_client = mailgun.client({
            username: 'api',
            key: MAILGUN_API_KEY,
            url: MAILGUN_API_URL //as provided by Dashboard: 'https://api.eu.mailgun.net/v3/m.domain.com'
        })

This doesn't work now and it's confusing for new users.

Callback is called twice instead of once (on error)

I'm playing around with attachments, trying to add multiple attachments to my email. I've got an error Error: 'from' parameter is missing as a response from the mailgun server, and I'll figure out why (I do give the from parameters, and emails get sent fine when I remove attachments).

The issue is that my callback gets called twice, with two different errors. I disabled retries.

  • First error: Error: 'from' parameter is missing <- message from mailgun servers
  • Second error: Error: write EPIPE <- connection error

As far as I can tell, this comes from the fact that the form-data module sends the two errors, one after the other.

In lib/request.js:

Request.prototype.performRequest = function (options) {
  var self = this;
  var method = options.method;

  if (this.form && (method === 'POST' || method === 'PUT' || method === 'PATCH')) {

    this.form.submit(options, function (err, res) {
      if (err) {
        return self.callback(err); // SECOND CALLBACK (first is below)
      }

      return self.handleResponse(res);
    });
  }
  // ...

The callback of this.form.submit is called twice. The first without error, and self.handleResponse is called on a response with status code 400, which triggers this error:

   if (!error && res.statusCode !== 200) {
      var msg = body ? body.message || body.response : body || chunks || res.statusMessage;
      error = new Error(msg);
      error.statusCode = res.statusCode;
    }

    return self.callback(error, body); // FIRST CALLBACK

The second time the callback of this.form.submit, it is with the EPIPE error, which triggers another call to the callback, with the EPIPE error.

To clarify:

  • this.form.submit returns with a valid response (although it is an HTTP 400 response)
  • this.handleResponse is called
  • callback is called with an error (generated by this module at the end of this.handleResponse)
  • this.form.submit sends an error (EPIPE, as the connection is closed)
  • callback is called again with an error (the EPIPE error)

Method Not Allowed

I am getting the following error.

Method Not Allowed

The method is not allowed for the requested URL.

Failed to load https://api.mailgun.net/v3/sandbox2146b93a96474715afd0a83a508da304.mailgun.org/messages: Request header field Authorization is not allowed by Access-Control-Allow-Headers in preflight response

this is what I have.

var mailgun = require('mailgun.js')
var mg = mailgun.client({ username: 'myusername', key: process.env['key-ad156aaaaaaaaaaaaaaae42dcba658'] || 'key-ad156aaaaaaaaaaaaaaaaaaaaaaaacba658' })

 mg.messages.create('sandbox2146b93a96474715afd0a83a508da304.mailgun.org', {
        from: "Excited User <[email protected]>",
        to: ["[email protected]"],
        subject: "Hello",
        text: "Testing some Mailgun awesomness!",
        html: "<h1>Testing some Mailgun awesomness!</h1>"
      })
        .then(msg => console.log(msg)) // logs response data
        .catch(err => console.log(err)); // logs any error

thx in advance

EU domain

How can I address a domain in the EU region ?

Better error handling to not let the application crash

When using the mailgun lib and sending an E-Mail the whole application can crash in result of an error.
I'd expect, that the lib will log an error and not let the app crash. That's bad, if it occurs a few hours after in runtime.

2020-11-09_14-01-10

validate email

Hello,
How can i have complet test ?
mailbox_verification to true ?
and / or syntax_only to false
thanks

Can't use a comma in the 'from' heading when sending an email

I would like the from field to have a comma when displaying the "name" in the users email.

Excited, User <[email protected]> but its turns into User <[email protected]>

Below is my code: (notice the comma in the from field)

mg.messages.create('sandbox-123.mailgun.org', {
    from: "Excited, User <[email protected]>",
    to: ["[email protected]"],
    subject: "Hello",
    text: "Testing some Mailgun awesomness!"
    html: "<h1>Testing some Mailgun awesomness!</h1>"
  })
  .then(msg => console.log(msg)) // logs response data 
  .catch(err => console.log(err)); // logs any error 

how to send mime email?

I've tried to follow readme, but is not working

const mail = new MailComposer(message).compile();

const data = {
    mime: true,
   message: mail.build(),
from,
to,
subject
}
TypeError [ERR_INVALID_ARG_TYPE]: The "chunk" argument must be one of type string or Buffer. Received type boolean

Mailgun send doesn't work

My node js server is 7, running two instances in AWS, from one instance sending the email is working, also when sending from localhost, but for the second instance didn't send, no error or buddy callback, could you help please ?

BCC

Trying to make all recipients be BCC, but when i leave out to and just put 'bcc' it gives me an error saying there has to be a to.
So i added both fields "to" and "bcc" with the same comma seperated email addresses, but all of the email addresses are being shown to the user in the actual email.

How do i set bcc recipients?

How to send the X-My-Header variables?

I'm trying to send a message with an email template but I can't figure where to add X-My-Header and its variables in order to add dynamic data to the template.

This is the code:

mg.messages.create('domain', {
    from: 'mail',
    to: [email],
    subject: 'subject',
    template: 'template'
  })
  .then(res => console.log('Resolved >>>>> ', res))
  .catch(err => console.log('MAILGUN ERROR >>>> ', err))

Thanks.

Example doesn't work

I am trying to run the following example. Keep getting 404 error. I can send a message with curl using the same (my) credentials. Not sure what's going on. Thanks.

mg.messages.create('sandbox-123.mailgun.org', { from: "Excited User <[email protected]>", to: ["[email protected]"], subject: "Hello", text: "Testing some Mailgun awesomness!", html: "<h1>Testing some Mailgun awesomness!</h1>" }) .then(msg => console.log(msg)) // logs response data .catch(err => console.log(err)); // logs any error

How to send pgp/mime emails?

I'm trying to send encrypted emails via mailgun-js but passing the option of 'h:Content-Type': multipart/encrypted; protocol="application/pgp-encrypted"; doesn't do anything. I'm assuming it's calling out to /messages rather than /messages.mime (which would ignore content-type), but even if it did that the mailgun docs indicate that you need to pass a multipart/form-data encoding.

Any ideas?

adding user-variables to messages

Hello!

I can't find any documentation or references to attaching user-variables to messages (v:myvar=myvalue using the HTTP API) - is this possible or planned?

Is 'Add member to a list' supported by the nodejs SDK?

I see the lists API is listed under the TODO in the readme file. However, when I read the docs here: https://documentation.mailgun.com/en/latest/api-mailinglists.html#examples I see nodejs examples for the list api.

Is this supported in the latest released version of the nodejs SDK?

Also, for your information, I tried making the call using native Javascript xhr and jQuery ajax requests. I haven't tried the Mailgun Javascript SDK. Would be great if you guys can add support for native Javascript. For this, you would have to support another call OPTIONS for the preflight request. Read more here: https://www.html5rocks.com/en/tutorials/cors/

Project link is wrong

The current title points to this NPM project: https://www.npmjs.com/package/mailgun.js . The original project is now unmaintained and suffering from a security issue on a dependency.

This should probably be updated with the correct link. If there isn't one should it be @maingub/mailgun-js ?

Edit: Actually, looking at the state of the code, the issues and pull requests, is this even being maintained? Makes me concerned as to keeping mailgun as a provider.

Security - Protecting API Key

Hi, I would like to know if there are any measures to protect the API Key, and prevent a third party from using the API Key to send mail?

Thank you.

Repository should be marked deprecated

Given the lack of maintenance, the outdated package dependencies with tons of vulnerabilities, the lack of support of the recent API version, new webhooks, etc. nobody should start development using this repo.

unsubscribe from specific tag or campaign

Is there a way that I can send regulate emails via malign, but some time I want to send special campaign emails which I can allow the user to unsubscribe from. But if the user unsubscribe from the special campaign email I want still to be able to send him the regular emails. I plan to send an HTML file as the email, is there away toy can automatically append the unsubscribe ? Is there example how to do it?

Also if user decide to unsubscribe, is there away that my web server via webhook or other way can be notified that the user unsubscribed from the the campaign?

Batch sending is not working

Hello,
In my following code example, I am trying to pass recipient-variables for batch sending (Domain, API key and emails have been modified from actual values).

var mailgun = require('mailgun.js');
var mg = mailgun.client({username: 'api', key: 'key-12345678912345678234567'});
var rvars = {
    '[email protected]': {
        subject: 'custom subject',
        message: 'custom message',
    }
};
mg.messages.create('domain.tld', {
        from: "[email protected]",
        to: ["[email protected]"],
        subject: '%recipient.subject%',
        html: '%recipient.message%',
        'recipient-variables': rvars,
    })
    .then(msg => console.log(msg)) // logs response data
    .catch(err => console.log(err)); // logs any error

I get the following error when I include recipient-variables or even recipientVariables

$ node batch.js
/Users/username/dev/mgex/node_modules/mailgun.js/node_modules/popsicle/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/lib/delayed_stream.js:33
  source.on('error', function() {});
         ^

TypeError: source.on is not a function
    at Function.DelayedStream.create (/Users/username/dev/mgex/node_modules/mailgun.js/node_modules/popsicle/node_modules/form-data/node_modules/combined-stream/node_modules/delayed-stream/lib/delayed_stream.js:33:10)
    at FormData.CombinedStream.append (/Users/username/dev/mgex/node_modules/mailgun.js/node_modules/popsicle/node_modules/form-data/node_modules/combined-stream/lib/combined_stream.js:43:37)
    at FormData.append (/Users/username/dev/mgex/node_modules/mailgun.js/node_modules/popsicle/node_modules/form-data/lib/form_data.js:43:3)
    at /Users/username/dev/mgex/node_modules/mailgun.js/lib/request.js:117:18
    at Array.forEach (native)
    at Request.postMulti (/Users/username/dev/mgex/node_modules/mailgun.js/lib/request.js:111:23)
    at MessagesClient.create (/Users/username/dev/mgex/node_modules/mailgun.js/lib/messages.js:21:27)
    at Object.<anonymous> (/Users/username/dev/mgex/batch.js:9:13)
    at Module._compile (module.js:435:26)
    at Object.Module._extensions..js (module.js:442:10)

If I remove recipient-variables then the mail is sent just fine. How does batch sending work with this library?

Is it possible to include an Avatar?

When I look in my Google inbox most companies have their logo to the left hand side. Is this possible with mailgun-js?

For example here is an email I received from Medium.com, you can see the logo on the left hand side.

Screenshot_20201121-170816_Gmail

how to track clicks,opens ?

hi

@k-pom @eddywashere @eddywashere @atarola @amatai

any of you guys pls tell how to track clicks and opens of the mail for the following nodejs code?. i use html as front end.

app.post('/', function(req, res) {
    var api_key = 'key-XXXXXxxxxxxxxXXXXXX';
    var domain = 'domain.in';
    var Mailgun = require('mailgun-js');
    var mailgun = new Mailgun({ apiKey: api_key, domain: domain });
    
    var data = {
        from: "[email protected]",
        to: "[email protected]",        
        subject: req.body.subject,       
        text: req.body.plaintext,
        'o:tag': req.body.tag
    };
    console.log(req.body);
    mailgun.messages().send(data, function(error, body) {
        console.log(body);
        //Email not sent
        if (error) {
            res.render('index', { title: 'No Email', msg: 'faild.', err: true })
        }        
        else {
            res.render('index', { title: 'Sent Email', msg: 'success.', err: false })
        }
    });
});

TypeError: Cannot read property 'path' of undefined

  1. What version of the module is the issue happening on? Does the issue happen on latest version?
    2.0.1

  2. What platform and Node.js version? (For example Node.js 6.9.1 on Mac OS X)
    NodeJs 8.1.2 Windows 7 64 Bit

  3. Does the action work when you manually perform request against mailgun using curl (or other means)?

  4. Sample source code or steps to reproduce
    import * as fs from 'fs';
    const mailgunClient = require('mailgun.js');

export default class MailClient {
constructor(config) {

    let mailgunConfig = config.mailgun;
    this.domain = mailgunConfig.domain;
    this.mailgun = mailgunClient.client({ username: 'api', key: mailgunConfig.api_key });

}

sendEmailConfirm(to, confirmToken) {

    try {
        let that = this;

        const path = require('path');
        fs.readFile(path.resolve(__dirname, '../templates/confirm.html'), 'utf8', function (err, html) {

            if(err){
                console.log(err);
            }
            
            //html.replace('{token}', confirmToken);
            //html.replace('{to}', to);
            let stringHtml = html.toString();
            
            that.mailgun.messages.create(that.domain, {
                from: "Excited User <[email protected]>",
                to: [to],
                subject: "Hello",
                text: "Verify your email address for ",
                html: stringHtml
            })
                .then(msg => console.log(msg)) // logs response data
                .catch(err => console.log(err)); // logs any error

        });
    } catch (error) {
        throw error;
    }
}

}

(Write description of your issue here, stack traces from errors and code that reproduces the issue are helpful)

:\Labs\service-user-profile\node_modules\popsicle\node_modules\form-data\lib\form_data.js:151
if (options.filename || value.path) {
^

TypeError: Cannot read property 'path' of undefined
at FormData._multiPartHeader (D:\Labs\service-user-profile\node_modules\popsicle\node_modules\form-data\lib\form_data.js:151:34)
at FormData.append (D:\Labs\service-user-profile\node_modules\popsicle\node_modules\form-data\lib\form_data.js:39:21)
at D:\Labs\service-user-profile\node_modules\mailgun.js\lib\request.js:114:20
at Array.forEach (native)
at D:\Labs\service-user-profile\node_modules\mailgun.js\lib\request.js:113:19
at Array.forEach (native)
at Request.postMulti (D:\Labs\service-user-profile\node_modules\mailgun.js\lib\request.js:111:23)
at MessagesClient.create (D:\Labs\service-user-profile\node_modules\mailgun.js\lib\messages.js:21:27)
at D:/Labs/service-user-profile/src/lib/mail-client.js:29:39
at tryToString (fs.js:512:3)
at FSReqWrap.readFileAfterClose [as oncomplete] (fs.js:500:12)

How to download attachment of incoming emails

i get the my incoming emails using mailgun on my site. i recivied the attachment josn object. i want to donwload the attachment from url object. but i am not able to access the attachment. how i can get the attached file of incoming emails. may i need to add user key or any other thing?
My reciving attachment object is
{ url: https://se.api.mailgun.net/v3/domains/mg.test.com/messages/eyJwIjpmYWxzZSwiayI6IjNhNjdlMWIxLWY│4MTAtNGFjZC1iMTkzLTc2Y2RmMjY3ZTdmYSIsInMiOiI0ZDQwMDkwYmI4IiwiYyI6InRhbmtiIn0=/attachments/0', 'content-type': 'image/jpeg',name: 'word.jpg', size: 6222 }
i am using this code to access my file.
var request = https.get(url, function(err,response) {
if(err){
console.info("Erro is",err);
}
else{
console.info("resp",response);
response.pipe(myFile);
}
});

send mime does not work

mg.messages.create('sandbox-123.mailgun.org', {
from: "Excited User [email protected]",
to: ["[email protected]"],
subject: "Hello",
message: ""
})
.then(msg => console.log(msg)) // logs response data
.catch(err => console.log(err)); // logs any error

this throw error

Need at least one of 'text' or 'html' parameters specified

when passing only message it does not work

when passing both text and html it does not send the MIME

Unfriendly error when trying to use unverified Mailgun account

I set up new Mailgun account, but in my haste to get it up and running, I didn't realize right away that I was supposed to check my email to verify the account. So I set up the library and was getting the unfriendly error: Warning: a promise was rejected with a non-error

Didn't realize the issue until I checked logs at Mailgun where the rejection reason was "Please activate your Mailgun account. Check your inbox or log in to your control panel to resend the activation email."

I know this one was my bad, but in general it would be nice to receive an error for a rejected email -- with the rejection reason included.

EDIT: Also occurred after account was flagged for business verification (rejection reason "Business Verification").

Relevant fields in the response are...

{
  "event": "rejected",
  "reject": {
    "reason": "Whatever the reason is...",
  }
}

how do you create a list?

adding a member to a list works, but how to you create a list that does not exist via this api wrapper?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.