mailgun / mailgun.js

Javascript SDK for Mailgun
https://www.npmjs.com/package/mailgun.js
Apache License 2.0
521 stars 110 forks source link

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

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.

IMPORTANT: if you are using EU infrastructure, you need to also pass url: 'https://api.eu.mailgun.net' together with auth credentials as stated in Mailgun docs

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 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'});

Using Subaccounts

Primary accounts can make API calls on behalf of their subaccounts. API documentation

  import 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'});
  mg.setSubaccount('subaccount-id');
  // then, if you need to reset it back to the primary account:
  mg.resetSubaccount();

Proxy configuration

By leveraging client configuration options, users can effortlessly establish proxy connections that align with their network requirements. Ex:

  import 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',
    proxy: {
      protocol: 'https' // 'http' ,
      host: '127.0.0.1', // use your proxy host here
      port: 9000, // use your proxy port here
      auth: { // may be omitted if proxy doesn't require authentication
        username: 'user_name', // provide username
        password: 'user_password' // provide password
      }
    },
  });

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:

Messages

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.

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 <mailer@mailer.example.com>',
      to: ['me@example.com', 'you@example.com'],
      subject: 'Recipient - %recipient.title%',
      html: 'Here\'s %recipient.title% and <a href="https://github.com/mailgun/mailgun.js/blob/master/%recipient.link%">link</a>',
      'recipient-variables': JSON.stringify({
        'me@example.com': {
          title: 'Me',
          link: 'href-var',
        },
        'you@example.com': {
          title: 'You',
          link: 'slug-recipient-var-c',
        },
      }),
    };

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

Domains

Events

Stats

Suppressions

Webhooks

Routes

Validation

Multiple validation

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

Mailing lists

A client to manage mailing lists.

Mailing list members

A client to manage members within a specific mailing list.

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: 'test-0@example.com',
          name: 'test name 0',
          subscribed: true,
          vars: [Object]
        },
        {
          address: 'test-1@example.com',
          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: 'test-1@example.com',
          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: 'test-0@example.com',
          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: 'test-2@example.com',
          name: 'test name 2',
          subscribed: true,
          vars: [Object]
        },
        {
          address: 'test-3@example.com',
          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: 'test-3@example.com',
          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: 'test-2@example.com',
          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

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.