Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bulk sending api #39

Merged
merged 16 commits into from
Jun 13, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ Refer to the [`examples`](examples) folder for the source code of this and other
- [Projects](examples/testing/projects.ts)
- [Send mail using template](examples/testing/template.ts)

### Bulk sending API

- [Send mail](examples/bulk/send-mail.ts)

### Nodemailer Transport

> NOTE: [Nodemailer](https://www.npmjs.com/package/nodemailer) is needed as a dependency.
Expand Down
22 changes: 22 additions & 0 deletions examples/bulk/send-mail.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { MailtrapClient } from "mailtrap"

/**
* For this example to work, you need to set up a sending domain,
* and obtain a token that is authorized to send from the domain.
* @see https://help.mailtrap.io/article/69-sending-domain-setup
*/

const TOKEN = "<YOUR-TOKEN-HERE>";
const SENDER_EMAIL = "<SENDER@YOURDOMAIN.COM>";
const RECIPIENT_EMAIL = "<RECIPIENT@EMAIL.COM>";

const client = new MailtrapClient({ token: TOKEN });

client.bulk.send({
from: { name: "Mailtrap Test", email: SENDER_EMAIL },
to: [{ email: RECIPIENT_EMAIL }],
subject: "Hello from Mailtrap!",
text: "Welcome to Mailtrap Sending!",
})
.then(console.log)
.catch(console.error);
146 changes: 146 additions & 0 deletions src/__tests__/lib/api/Bulk.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import axios from "axios";
import AxiosMockAdapter from "axios-mock-adapter";

import BulkAPI from "../../../lib/api/Bulk";
import handleSendingError from "../../../lib/axios-logger";
import MailtrapError from "../../../lib/MailtrapError";

import CONFIG from "../../../config";

const { CLIENT_SETTINGS } = CONFIG;
const { BULK_ENDPOINT } = CLIENT_SETTINGS;

describe("lib/api/Bulk: ", () => {
let mock: AxiosMockAdapter;
const bulkAPI = new BulkAPI(axios);

describe("class Testing(): ", () => {
describe("init: ", () => {
it("initalizes with all necessary params.", () => {
expect(bulkAPI).toHaveProperty("send");
});
});

beforeAll(() => {
/**
* Init Axios interceptors for handling response.data, errors.
*/
axios.interceptors.response.use(
(response) => response.data,
handleSendingError
);
mock = new AxiosMockAdapter(axios);
});

afterEach(() => {
mock.reset();
});

describe("send(): ", () => {
it("successfully sends email.", async () => {
const endpoint = `${BULK_ENDPOINT}/api/send`;
const expectedResponseData = {
success: true,
message_ids: ["0c7fd939-02cf-11ed-88c2-0a58a9feac02"],
};
mock.onPost(endpoint).reply(200, expectedResponseData);

const emailData = {
from: {
email: "sender.mock@email.com",
name: "sender",
},
to: [
{
email: "recipient.mock@email.com",
name: "recipient",
},
],
subject: "mock-subject",
text: "Mock text",
html: "<div>Mock text</div>",
};

const result = await bulkAPI.send(emailData);

expect(mock.history.post[0].url).toEqual(endpoint);
expect(mock.history.post[0].data).toEqual(JSON.stringify(emailData));
expect(result).toEqual(expectedResponseData);
});

it("handles an API error.", async () => {
const responseData = {
success: false,
errors: ["mock-error-1", "mock-error-2"],
};

const endpoint = `${BULK_ENDPOINT}/api/send`;

mock.onPost(endpoint).reply(400, responseData);

const emailData = {
from: {
email: "sender.mock@email.com",
name: "sender",
},
to: [
{
email: "recipient.mock@email.com",
name: "recipient",
},
],
subject: "mock-subject",
text: "Mock text",
html: "<div>Mock text</div>",
};

const expectedErrorMessage = responseData.errors.join(",");

expect.assertions(3);

try {
await bulkAPI.send(emailData);
} catch (error) {
expect(mock.history.post[0].url).toEqual(endpoint);
expect(mock.history.post[0].data).toEqual(JSON.stringify(emailData));

if (error instanceof Error) {
expect(error.message).toEqual(expectedErrorMessage);
}
}
});

it("handles an HTTP transport error.", async () => {
const emailData = {
from: {
email: "sender.mock@email.com",
name: "sender",
},
to: [
{
email: "recipient.mock@email.com",
name: "recipient",
},
],
subject: "mock-subject",
text: "Mock text",
html: "<div>Mock text</div>",
};

const expectedErrorMessage = "Request failed with status code 404";

expect.assertions(2);

try {
await bulkAPI.send(emailData);
} catch (error) {
expect(error).toBeInstanceOf(MailtrapError);

if (error instanceof MailtrapError) {
expect(error.message).toEqual(expectedErrorMessage);
}
}
});
});
});
});
4 changes: 2 additions & 2 deletions src/__tests__/lib/api/Testing.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ describe("lib/api/Testing: ", () => {
expect(result).toEqual(expectedResponseData);
});

it("rejects with api error.", async () => {
it("handles an API error.", async () => {
const responseData = {
success: false,
errors: ["mock-error-1", "mock-error-2"],
Expand Down Expand Up @@ -115,7 +115,7 @@ describe("lib/api/Testing: ", () => {
}
});

it("rejects with axios error.", async () => {
it("handles an HTTP transport error.", async () => {
const emailData = {
from: {
email: "sender.mock@email.com",
Expand Down
1 change: 1 addition & 0 deletions src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export default {
},
CLIENT_SETTINGS: {
SENDING_ENDPOINT: "https://send.api.mailtrap.io",
BULK_ENDPOINT: "https://bulk.api.mailtrap.io",
TESTING_ENDPOINT: "https://sandbox.api.mailtrap.io",
GENERAL_ENDPOINT: "https://mailtrap.io",
USER_AGENT:
Expand Down
8 changes: 6 additions & 2 deletions src/lib/MailtrapClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import axios, { AxiosInstance } from "axios";

import encodeMailBuffers from "./mail-buffer-encoder";
import handleSendingError from "./axios-logger";

import GeneralAPI from "./api/General";
import TestingAPI from "./api/Testing";
import BulkAPI from "./api/Bulk";

import CONFIG from "../config";

Expand All @@ -31,6 +33,8 @@ export default class MailtrapClient {

public general: GeneralAPI;

public bulk: BulkAPI;

/**
* Initalizes axios instance with Mailtrap params.
*/
Expand Down Expand Up @@ -58,15 +62,15 @@ export default class MailtrapClient {
this.accountId = accountId;

/**
* Initialize testing API.
* Initialize APIs.
*/
this.testingAPI = new TestingAPI(
this.axios,
this.testInboxId,
this.accountId
);

this.general = new GeneralAPI(this.axios, this.accountId);
this.bulk = new BulkAPI(this.axios);
}

/**
Expand Down
25 changes: 25 additions & 0 deletions src/lib/api/Bulk.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { AxiosInstance } from "axios";

import encodeMailBuffers from "../mail-buffer-encoder";

import CONFIG from "../../config";

import { Mail, SendResponse } from "../../types/mailtrap";

const { CLIENT_SETTINGS } = CONFIG;
const { BULK_ENDPOINT } = CLIENT_SETTINGS;

export default class BulkAPI {
private client: AxiosInstance;

constructor(client: AxiosInstance) {
this.client = client;
}

public async send(mail: Mail): Promise<SendResponse> {
const url = `${BULK_ENDPOINT}/api/send`;
const preparedMail = encodeMailBuffers(mail);

return this.client.post<SendResponse, SendResponse>(url, preparedMail);
}
}
Loading