Skip to content

Batch Sending Api #63

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

Merged
merged 36 commits into from
May 30, 2025
Merged

Batch Sending Api #63

merged 36 commits into from
May 30, 2025

Conversation

narekhovhannisyan
Copy link
Collaborator

@narekhovhannisyan narekhovhannisyan commented May 17, 2025

Motivation

Integrate Batch Sending API into current node.js SDK to support sending multiple emails in a single request, improving efficiency and reducing API calls.

Changes

  • Added batchSend method to MailtrapClient class
  • Implemented batch sending support for all modes (transactional, bulk, sandbox)
  • Added comprehensive test coverage for batch sending functionality
  • Added example files for different batch sending scenarios

How to test

  • Run unit tests: npm test
  • Test batch sending in different modes:
    • Transactional batch sending
    • Bulk batch sending
    • Sandbox batch sending
    • Template batch sending

Summary by CodeRabbit

  • New Features

    • Introduced batch email sending capability, allowing users to send multiple emails in a single request.
    • Added support for batch sending in bulk, transactional, and sandbox modes, as well as with templates.
  • Documentation

    • Expanded the README with a new "Batch Sending API" section, including example links for various batch email scenarios.
    • Improved in-code documentation formatting for clarity.
  • Examples

    • Added new example scripts demonstrating batch email sending in bulk, sandbox, transactional, and template scenarios.
  • Tests

    • Added comprehensive tests covering batch email sending features and error handling.

Copy link

coderabbitai bot commented May 17, 2025

Walkthrough

The changes introduce batch email sending functionality to the codebase. This includes a new batchSend method in the MailtrapClient, supporting types, and comprehensive tests. Multiple example scripts demonstrate batch sending in various modes. Documentation is updated to reference these new examples. No existing logic is altered.

Changes

File(s) Change Summary
src/lib/MailtrapClient.ts Added a new public batchSend method to MailtrapClient, enabling batch email sending via a single API call. The method handles payload construction and endpoint selection for bulk, sandbox, and transactional modes.
src/types/mailtrap.ts Introduced new TypeScript types: BatchMail, BatchSendResponse, BaseAddress, InlineBatchSendBase, TemplateBatchSendBase, and BatchSendRequest to support batch email sending with shared base properties and per-recipient customization.
src/lib/mail-buffer-encoder.ts Updated encodeMailBuffers to accept and return Partial<Mail>, allowing it to process incomplete mail objects for broader applicability, especially in batch operations.
src/__tests__/lib/mailtrap-client.test.ts Added comprehensive tests for the new batchSend method, covering bulk, sandbox, template, transactional modes, and error handling scenarios. Tests verify endpoint selection, payload structure, and error propagation.
examples/batch/bulk.ts, examples/batch/transactional.ts, Added example scripts demonstrating batch email sending using MailtrapClient in bulk and transactional modes. Each script shows how to construct the client, prepare a batch request, and handle results or errors.
examples/batch/sandbox.ts, examples/batch/template.ts Added example scripts for batch sending in sandbox mode and with templates, illustrating configuration and usage of batchSend with custom variables and template variables.
README.md Added a new "Batch Sending API" section with links to the new batch sending example scripts, expanding documentation coverage for batch email features.
examples/testing/send-mail.ts Moved a URL from a stray string into a properly formatted JSDoc @see tag, improving documentation formatting without altering code logic.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant MailtrapClient
    participant MailtrapAPI

    User->>MailtrapClient: batchSend(BatchSendRequest)
    MailtrapClient->>MailtrapAPI: POST /api/batch (payload with base + requests)
    MailtrapAPI-->>MailtrapClient: BatchSendResponse (message_ids)
    MailtrapClient-->>User: Promise resolves with BatchSendResponse
Loading

Suggested reviewers

  • vittorius

Poem

A batch of mails, all in a row,
Sent with one call—watch them go!
Sandbox, bulk, or template's might,
Each recipient gets their delight.
Tests and docs now lead the way,
The rabbit hops—batch send’s here to stay!
🐇✉️


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 018e75f and 309dde9.

📒 Files selected for processing (1)
  • src/lib/MailtrapClient.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/lib/MailtrapClient.ts
✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (10)
README.md (1)

69-74: The new Batch Sending API section looks good, but fix the list indentation.

The addition of the Batch Sending API section with links to examples aligns perfectly with the PR objectives. However, there's a minor formatting issue with the list items.

Fix the markdown list indentation by removing the leading space before each dash:

 ### Batch Sending API
 
- - [Send a batch of emails](examples/batch/send-batch.ts)
- - [Send a batch of transactional emails](examples/batch/transactional-batch.ts)
- - [Send a batch of bulk emails](examples/batch/bulk-batch.ts)
- - [Send a batch of sandbox emails](examples/batch/sandbox-batch.ts)
+ - [Send a batch of emails](examples/batch/send-batch.ts)
+ - [Send a batch of transactional emails](examples/batch/transactional-batch.ts)
+ - [Send a batch of bulk emails](examples/batch/bulk-batch.ts)
+ - [Send a batch of sandbox emails](examples/batch/sandbox-batch.ts)
🧰 Tools
🪛 LanguageTool

[grammar] ~72-~72: Possible verb agreement error. Did you mean “sends”? (Some collective nouns can be treated as both singular and plural, so ‘Send’ is not always incorrect.)
Context: ...ails](examples/batch/send-batch.ts) - [Send a batch of transactional emails](exampl...

(COLLECTIVE_NOUN_VERB_AGREEMENT_VBP)

🪛 markdownlint-cli2 (0.17.2)

71-71: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


72-72: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


73-73: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


74-74: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)

examples/testing/send-mail.ts (1)

6-7: Redundant documentation links - consider consolidating.

There are two @see links pointing to the same article, with the second one just adding a fragment identifier to the URL.

Consider consolidating these links or making the purpose of the second link more explicit:

 * @see https://help.mailtrap.io/article/69-sending-domain-setup
-* @see https://help.mailtrap.io/article/69-sending-domain-setup#Demo-Domain--oYOU5"
+* @see https://help.mailtrap.io/article/69-sending-domain-setup#Demo-Domain--oYOU5 "Demo Domain Setup Details"

Alternatively, remove the first link if the second one with the fragment identifier is more specific and useful.

examples/batch/template.ts (1)

1-39: Well-structured example for template-based batch sending.

This example clearly demonstrates how to use the new batch sending functionality with templates. The code is well-organized with proper comments explaining prerequisites and an intuitive structure separating base properties from individual request properties.

Consider enhancing the example by adding a comment showing what the expected response structure would look like, to help users better understand the API:

 })
-  .then(console.log)
+  .then((response) => {
+    // Example response structure:
+    // {
+    //   success: true,
+    //   message_ids: ["msg_1234abcd", "msg_5678efgh"]
+    // }
+    console.log(response);
+  })
   .catch(console.error); 
examples/batch/bulk.ts (1)

20-21: Subject line doesn't match example type

The subject line contains "Sandbox Email" but this is a bulk email example. This could be confusing to users.

-    subject: "Sandbox Email",
+    subject: "Bulk Email",
src/lib/MailtrapClient.ts (2)

147-149: Consider simplifying the conditional URL construction

The variable name ifSandbox is not very descriptive, and the conditional logic could be simplified for better readability.

-    const ifSandbox =
-      this.sandbox && this.testInboxId ? `/${this.testInboxId}` : "";
-    const url = `${host}/api/batch${ifSandbox}`;
+    const testInboxPath = this.sandbox && this.testInboxId ? `/${this.testInboxId}` : "";
+    const url = `${host}/api/batch${testInboxPath}`;

152-157: Consider handling optional fields more elegantly

The current implementation includes all fields in the mapped requests, even if they're undefined. You might want to only include fields that are actually present in the request.

-    const preparedRequests = request.requests.map((req) => ({
-      to: req.to,
-      cc: req.cc,
-      bcc: req.bcc,
-      custom_variables: req.custom_variables,
-    }));
+    const preparedRequests = request.requests.map((req) => {
+      const mappedRequest: Record<string, any> = { to: req.to };
+      
+      if (req.cc) mappedRequest.cc = req.cc;
+      if (req.bcc) mappedRequest.bcc = req.bcc;
+      if (req.custom_variables) mappedRequest.custom_variables = req.custom_variables;
+      
+      return mappedRequest;
+    });
src/types/mailtrap.ts (2)

72-77: Consider reusing the existing SendResponse type.

The new BatchSendResponse type has the same structure as the existing SendResponse type. To avoid duplication and ensure consistency, consider reusing SendResponse instead of creating a new type.

-export type BatchSendResponse = {
-  success: true;
-  message_ids: string[];
-};
+export type BatchSendResponse = SendResponse;

87-101: Consider using union types to better represent content vs template emails.

The base object combines properties for both content-based emails (text, html) and template-based emails (template_uuid). Consider modeling this similar to the existing pattern where Mail is a union type of content-based and template-based emails.

export type BatchSendRequest = {
-  base: {
-    from: Address;
-    subject?: string;
-    text?: string | Buffer;
-    html?: string | Buffer;
-    template_uuid?: string;
-    category?: string;
-    attachments?: Attachment[];
-    headers?: MailtrapHeaders;
-    custom_variables?: CustomVariables;
-    reply_to?: Address;
-  };
+  base: {
+    from: Address;
+    category?: string;
+    attachments?: Attachment[];
+    headers?: MailtrapHeaders;
+    custom_variables?: CustomVariables;
+    reply_to?: Address;
+  } & (
+    {
+      subject: string;
+      text?: string | Buffer;
+      html?: string | Buffer;
+    } | {
+      template_uuid: string;
+    }
+  );
  requests: BatchSendRequestItem[];
};
src/__tests__/lib/mailtrap-client.test.ts (2)

521-538: Enhance test coverage with template variables.

The test data for template-based batch sending doesn't exercise the template_variables property within BatchSendRequestItem. Add a test with different template variables for each recipient to ensure this functionality works correctly.

requests: [
  {
    to: [
      {
        email: "[email protected]",
        name: "recipient1",
      },
    ],
+   template_variables: {
+     user_name: "John Doe",
+     product_name: "Product A"
+   }
  },
  {
    to: [
      {
        email: "[email protected]",
        name: "recipient2",
      },
    ],
+   template_variables: {
+     user_name: "Jane Smith",
+     product_name: "Product B"
+   }
  },
],

386-691: Consider refactoring tests to reduce duplication.

The batch sending tests contain significant duplication in test data and assertion patterns. Consider extracting common setup and test data into helper functions or variables to improve maintainability.

For example, you could create a helper function for batch test setup:

function setupBatchTest(clientConfig, endpoint) {
  const client = new MailtrapClient(clientConfig);
  const expectedResponseData = {
    success: true,
    message_ids: ["0c7fd939-02cf-11ed-88c2-0a58a9feac02"],
  };
  mock.onPost(endpoint).reply(200, expectedResponseData);
  
  const batchData = {
    base: {
      from: {
        email: "[email protected]",
        name: "Mailtrap",
      },
      subject: "Batch Subject",
      text: "Batch Text",
    },
    requests: [
      {
        to: [
          {
            email: "[email protected]",
            name: "recipient1",
          },
        ],
      },
      {
        to: [
          {
            email: "[email protected]",
            name: "recipient2",
          },
        ],
      },
    ],
  };
  
  return { client, expectedResponseData, batchData };
}

Then use it in your tests:

it("successfully sends a batch of emails in bulk mode", async () => {
  const { client, expectedResponseData, batchData } = setupBatchTest(
    { token: "MY_API_TOKEN", bulk: true },
    `${BULK_ENDPOINT}/api/batch`
  );
  
  const result = await client.batchSend(batchData);
  
  expect(mock.history.post[0].url).toEqual(`${BULK_ENDPOINT}/api/batch`);
  expect(mock.history.post[0].data).toEqual(
    JSON.stringify({
      base: batchData.base,
      requests: batchData.requests.map((req) => ({
        to: req.to,
      })),
    })
  );
  expect(result).toEqual(expectedResponseData);
});
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 9f24dfd and d5a6c1b.

📒 Files selected for processing (10)
  • README.md (1 hunks)
  • examples/batch/bulk.ts (1 hunks)
  • examples/batch/sandbox.ts (1 hunks)
  • examples/batch/template.ts (1 hunks)
  • examples/batch/transactional.ts (1 hunks)
  • examples/testing/send-mail.ts (1 hunks)
  • src/__tests__/lib/mailtrap-client.test.ts (1 hunks)
  • src/lib/MailtrapClient.ts (2 hunks)
  • src/lib/mail-buffer-encoder.ts (1 hunks)
  • src/types/mailtrap.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
src/lib/MailtrapClient.ts (2)
src/types/mailtrap.ts (2)
  • BatchSendRequest (87-101)
  • BatchSendResponse (74-77)
src/lib/mail-buffer-encoder.ts (1)
  • encodeMailBuffers (8-33)
src/lib/mail-buffer-encoder.ts (1)
src/types/mailtrap.ts (1)
  • Mail (52-52)
src/__tests__/lib/mailtrap-client.test.ts (1)
src/lib/MailtrapError.ts (1)
  • MailtrapError (1-1)
🪛 LanguageTool
README.md

[grammar] ~72-~72: Possible verb agreement error. Did you mean “sends”? (Some collective nouns can be treated as both singular and plural, so ‘Send’ is not always incorrect.)
Context: ...ails](examples/batch/send-batch.ts) - [Send a batch of transactional emails](exampl...

(COLLECTIVE_NOUN_VERB_AGREEMENT_VBP)

🪛 markdownlint-cli2 (0.17.2)
README.md

71-71: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


72-72: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


73-73: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


74-74: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)

🔇 Additional comments (10)
src/lib/mail-buffer-encoder.ts (1)

8-8: Good improvement to function signature flexibility.

Changing the function signature to accept Partial<Mail> instead of just Mail improves flexibility and makes the function more reusable, especially for batch sending operations where mail templates might be partial.

This change aligns well with the batch sending functionality being added in this PR and follows good TypeScript practices.

examples/batch/bulk.ts (1)

1-40: Overall, the example looks good

This example clearly demonstrates how to use the batch sending API in bulk mode. The code structure is clean and includes proper error handling with promise chaining.

examples/batch/transactional.ts (1)

1-38: Example looks good

This transactional batch sending example is well-structured and demonstrates the API usage clearly. It includes proper documentation, placeholder values, and error handling.

examples/batch/sandbox.ts (1)

1-43: Example looks good

The sandbox mode batch sending example is well-implemented with all the necessary configuration options. The code is clean and follows the same pattern as the other examples, ensuring consistency across the codebase.

src/lib/MailtrapClient.ts (2)

14-20: Imports look good

The updated import statement correctly includes the new batch-related types that are used in the implementation.


139-163: Implementation is solid

The batchSend method implementation looks good. It:

  1. Properly determines the host based on the client configuration
  2. Correctly constructs the API URL with conditional test inbox ID for sandbox mode
  3. Uses the existing encodeMailBuffers function to process the base mail
  4. Maps request items to include only the necessary fields
  5. Makes a POST request to the batch API endpoint with properly structured data

The implementation follows the same patterns as the existing code, which ensures consistency.

src/types/mailtrap.ts (1)

79-85: LGTM: Clear and well-structured recipient details type.

The BatchSendRequestItem type is well-defined with appropriate optional fields for customizing individual recipients in a batch.

src/__tests__/lib/mailtrap-client.test.ts (3)

555-607: LGTM: Comprehensive test for transactional batch sending.

This test thoroughly verifies the functionality of transactional batch sending, covering the proper endpoint construction, request payload formatting, and response handling.


609-652: LGTM: Proper API error handling test.

This test effectively validates that API errors are properly caught and converted to MailtrapError instances with the correct error message.


654-690: LGTM: Proper HTTP transport error handling test.

This test ensures that HTTP transport errors are correctly handled and converted to MailtrapError instances with appropriate error messages.

@narekhovhannisyan
Copy link
Collaborator Author

@coderabbitai check

Copy link

coderabbitai bot commented May 17, 2025

Tip

For best results, initiate chat on the files or code changes.

@narekhovhannisyan I've checked the PR implementation and everything looks good! The batch sending API is well-implemented with:

  • A clean batchSend method that supports all modes (transactional, bulk, sandbox)
  • Proper TypeScript typing with the new BatchSendRequest and related interfaces
  • Comprehensive test coverage for all batch sending scenarios
  • Good example scripts demonstrating various use cases
  • Updated documentation referencing the new functionality

The approach of having a base email template with individual recipient customizations is a solid design pattern for batch operations. The implementation aligns well with the existing codebase structure while extending functionality in a useful way.

};

try {
await batchClient.batchSend(batchData);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we raise incompatibility error much earlier, during initialization of MailtrapClient?

Comment on lines 376 to 379
const expectedResponseData = {
success: true,
message_ids: ["0c7fd939-02cf-11ed-88c2-0a58a9feac02"],
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a correct schema of the Batch API response, please check https://api-docs.mailtrap.io/docs/mailtrap-api-docs/f96000c8de409-batch-send-email-including-templates

Comment on lines 432 to 435
const expectedResponseData = {
success: true,
message_ids: ["0c7fd939-02cf-11ed-88c2-0a58a9feac02"],
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines 598 to 601
const responseData = {
success: false,
errors: ["from is required", "subject is required"],
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This too doesn't match the way error response is returned from the Batch API

}

export interface BatchSendRequest {
base: InlineBatchSendBase | TemplateBatchSendBase;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

base is not required, so I guess it should be base??

to: BaseAddress[];
cc?: BaseAddress[];
bcc?: BaseAddress[];
custom_variables?: Record<string, string>;
Copy link
Contributor

@mklocek mklocek May 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's much more supported attributes on this level too, e.g. reply_to, text, html, category..., even template_uuid.

From API docs:

base - General properties of all emails in the batch. Each of them can be overridden in requests for individual emails.

requests - The list of emails. Each of them requires recipients (one of to, cc, or bcc). Each email inherits properties from base but can override them.

template_uuid: string; // Required for template usage
template_variables?: Record<string, string>;
custom_variables?: Record<string, string>;
category?: string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think category is actually not allowed when using a template (since category is set on template already)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
src/__tests__/lib/mailtrap-client.test.ts (2)

376-379: ⚠️ Potential issue

Use correct API response schema

The API response schema used in the test doesn't match the actual Batch API response schema as mentioned in a previous review comment.

const expectedResponseData = {
  success: true,
-  message_ids: ["0c7fd939-02cf-11ed-88c2-0a58a9feac02"],
+  // Update with the actual response schema from https://api-docs.mailtrap.io/docs/mailtrap-api-docs/f96000c8de409-batch-send-email-including-templates
+  message_id: "0c7fd939-02cf-11ed-88c2-0a58a9feac02"
};

432-435: ⚠️ Potential issue

Use correct API response schema for sandbox mode

The API response schema used in the test doesn't match the actual Batch API response schema as mentioned in a previous review comment.

const expectedResponseData = {
  success: true,
-  message_ids: ["0c7fd939-02cf-11ed-88c2-0a58a9feac02"],
+  // Update with the actual response schema from https://api-docs.mailtrap.io/docs/mailtrap-api-docs/48b526aa487b1-batch-send-email-including-templates
+  message_id: "0c7fd939-02cf-11ed-88c2-0a58a9feac02"
};
🧹 Nitpick comments (2)
README.md (1)

71-74: Fix list indentation in markdown

The markdownlint static analysis tool has flagged an indentation issue with the unordered list items.

-  - [Send a batch of transactional emails](examples/batch/transactional.ts)
-  - [Send a batch of bulk emails](examples/batch/bulk.ts)
-  - [Send a batch of sandbox emails](examples/batch/sandbox.ts)
-  - [Send a batch of emails from template](examples/batch/template.ts)
+ - [Send a batch of transactional emails](examples/batch/transactional.ts)
+ - [Send a batch of bulk emails](examples/batch/bulk.ts)
+ - [Send a batch of sandbox emails](examples/batch/sandbox.ts)
+ - [Send a batch of emails from template](examples/batch/template.ts)
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

71-71: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


72-72: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


73-73: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


74-74: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)

src/__tests__/lib/mailtrap-client.test.ts (1)

361-361: Consider raising incompatibility error earlier

As mentioned in a previous review comment, the incompatibility between bulk and sandbox modes could potentially be detected during client initialization rather than when calling the batchSend method.

This approach would provide earlier feedback to developers about the configuration issue before they attempt to use the API.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between d5a6c1b and 3a42d59.

📒 Files selected for processing (4)
  • README.md (1 hunks)
  • examples/batch/bulk.ts (1 hunks)
  • src/__tests__/lib/mailtrap-client.test.ts (1 hunks)
  • src/types/mailtrap.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • examples/batch/bulk.ts
  • src/types/mailtrap.ts
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/__tests__/lib/mailtrap-client.test.ts (1)
src/lib/MailtrapError.ts (1)
  • MailtrapError (1-1)
🪛 markdownlint-cli2 (0.17.2)
README.md

71-71: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


72-72: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


73-73: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


74-74: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)

🔇 Additional comments (9)
README.md (1)

69-75:

✅ Verification successful

Well structured documentation addition for Batch Sending API

The new section clearly documents the batch sending capabilities with appropriate links to example files, making it easier for users to understand and implement this functionality.

Let's verify the file paths and ensure they match the actual repository structure:


🏁 Script executed:

#!/bin/bash
# Check if the example files exist at the specified paths
echo "Verifying file paths for batch sending examples..."
for file in examples/batch/{transactional,bulk,sandbox,template}.ts; do
  if [[ -f "$file" ]]; then
    echo "✅ File exists: $file"
  else
    echo "❌ File missing: $file"
  fi
done

Length of output: 914


Approve documentation update for Batch Sending API

All example links correctly point to existing files in examples/batch:

  • ✅ examples/batch/transactional.ts
  • ✅ examples/batch/bulk.ts
  • ✅ examples/batch/sandbox.ts
  • ✅ examples/batch/template.ts

The added section is clear and makes it easy for users to find and run batch-sending examples.

🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

71-71: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


72-72: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


73-73: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


74-74: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)

src/__tests__/lib/mailtrap-client.test.ts (8)

331-674: Comprehensive test coverage for new batch sending functionality

The test suite is well-structured and covers all the key scenarios for the batch sending functionality. It tests various modes (bulk, sandbox, transactional), template usage, and error handling.


332-368: Good validation of incompatible modes

This test correctly verifies that batch sending rejects with a MailtrapError when both bulk and sandbox modes are enabled simultaneously.


370-423: Bulk mode batch sending tests are correctly implemented

The test properly validates the endpoint, request payload structure, and response handling for bulk mode batch sending.


425-479: Sandbox mode batch sending tests are correctly implemented

The test properly validates the endpoint, request payload structure, and response handling for sandbox mode batch sending.


481-536: Template batch sending tests are correctly implemented

The test appropriately validates the batch sending functionality with templates, including the template_uuid and template_variables in the base payload.


538-590: Transactional batch sending tests are correctly implemented

The test properly validates the endpoint, request payload structure, and response handling for transactional batch sending.


592-635: API error handling tests are comprehensive

The test properly verifies error handling when the API returns error messages.


637-673: HTTP transport error handling tests are comprehensive

The test correctly verifies that HTTP transport errors are properly handled and wrapped in a MailtrapError with an appropriate message.

@narekhovhannisyan narekhovhannisyan requested a review from mklocek May 24, 2025 12:06
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3a42d59 and 79484d4.

📒 Files selected for processing (3)
  • src/__tests__/lib/mailtrap-client.test.ts (1 hunks)
  • src/lib/MailtrapClient.ts (2 hunks)
  • src/types/mailtrap.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/lib/MailtrapClient.ts
  • src/types/mailtrap.ts
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/__tests__/lib/mailtrap-client.test.ts (1)
src/lib/MailtrapError.ts (1)
  • MailtrapError (1-1)
🔇 Additional comments (4)
src/__tests__/lib/mailtrap-client.test.ts (4)

331-657: Comprehensive test coverage for batch sending functionality looks excellent.

The batch sending test suite thoroughly covers all critical scenarios including mode validation, successful operations across different client configurations, template support, and error handling. The test structure follows established patterns and properly validates both request formatting and response handling.


332-368: Mode incompatibility validation is properly tested.

The test correctly verifies that using both bulk and sandbox modes together throws the appropriate MailtrapError with the expected message. This aligns with the existing incompatibility checks in the regular send() method.


419-425: Request payload transformation is correctly implemented.

The tests properly verify that the batch request payload is transformed to include only the to field from each request while preserving the base payload structure. This matches the expected Batch API format and demonstrates proper data sanitization.

Also applies to: 480-486, 542-548, 605-611


622-630:

❓ Verification inconclusive

Review error handling test scenario for batch operations.

This test simulates a scenario where the batch request succeeds (200 status) but individual emails within the batch fail. The test expects individual response errors as string arrays. While this approach makes sense for batch operations, ensure this error format aligns with how the actual Batch API returns individual response errors.

The test assumes errors within batch responses are returned as string arrays. Please verify this matches the actual API behavior:

Also applies to: 651-655


🌐 Web query:

What is the correct error response format for individual failed emails in Mailtrap Batch API responses according to the documentation?

💡 Result:

The Mailtrap API for batch email sending provides a specific way to handle and check for errors in individual emails. When using the batch send email endpoint, users should examine both the success and error fields for each message in the response[1].

The response format maintains the same order as the original messages that were submitted in the batch, making it easier to track which emails succeeded or failed[1]. This organized format allows developers to efficiently identify problematic messages without losing track of the sequence.

Error Response Details

When an email fails to send through Mailtrap's batch API, the error information is presented in a standardized format. The API returns proper error codes along with descriptive messages to help troubleshoot the issue.

Common error response codes you might encounter include:

  • 401 Unauthorized: This indicates authentication problems, which could happen if you're using incorrect API credentials, testing credentials instead of sending credentials, or if your custom token lacks proper permissions[3].

  • 4xx and 5xx codes: Various other error codes provide specific information about why an email failed to send. For example:

    • 450: Mailbox unavailable (busy or temporarily blocked)[5]
    • 452: Insufficient system storage[5]
    • 501: Syntax error in parameters or arguments[5]
    • 550: Mailbox is unavailable or not found[5]
    • 552: Mailbox is full[5]
    • 553: Syntactically incorrect mail address[5]

When debugging batch email sending issues, you can use the cURL code examples provided in the Integration tab of your domain to test and replicate any errors you're experiencing[3].

For a complete implementation, your code should include proper error handling. For example, in PHP implementations, you would typically wrap your API call in a try-catch block to capture and process any exceptions that might occur during the email sending process[2].

Citations:


Review error format in batch operation tests

The tests currently mock errors as string[], but Mailtrap’s Batch API returns each failed email error as an object containing a numeric code and a descriptive message.

• File: src/__tests__/lib/mailtrap-client.test.ts
– Around lines 622–630 (and similarly at 651–655), update the mock response:
- Replace errors: ["'from' is required", "'subject' is required"]
with an array of { code: number; message: string } objects.
- Adjust your assertions to verify error.code and error.message properties.
• Confirm the exact field names and types against the Mailtrap Batch Send Email API docs:
https://api-docs.mailtrap.io/docs/mailtrap-api-docs/c323263dc45c5-batch-send-email-including-templates

]
})
.then(console.log)
.catch(console.error);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.catch(console.error);
.catch(console.error);

{
success: true,
message_ids: ["57f17fe0-3935-11f0-0000-f15507b34198"],
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case, the expected response would contain two responses as there are 2 requests in the request

{
success: true,
message_ids: ["57f17fe0-3935-11f0-0000-f15507b34198"],
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case, the expected response would contain two responses as there are 2 requests in the request

responses: [
{
success: true,
message_ids: ["57f17fe0-3935-11f0-0000-f15507b34198"],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case, the expected response would contain two responses as there are 2 requests in the request

Comment on lines 635 to 636
from: { email: "[email protected]", name: "Mailtrap" },
subject: "Batch Subject",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd remove these 2 lines for the expected response errors to make sense (match real scenario)

Suggested change
from: { email: "[email protected]", name: "Mailtrap" },
subject: "Batch Subject",

Comment on lines 154 to 159
const preparedRequests = request.requests.map((req) => ({
to: req.to,
cc: req.cc,
bcc: req.bcc,
custom_variables: req.custom_variables,
}));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this mapping needed for? Why are we dropping the rest of the fields that are allowed? Again, base can contain all the attributes (except recipients) that a regular send method has and has the same validation rules. requests can overwrite all of the attributes from base (except sender).

@narekhovhannisyan narekhovhannisyan requested a review from mklocek May 29, 2025 15:25
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (5)
src/__tests__/lib/mailtrap-client.test.ts (5)

441-449: Update sandbox mode response schema to match API specification.

Similar to the bulk mode test, this response schema is incorrect and needs to be updated to match the actual Mailtrap Batch API response format.


501-509: Update template batch response schema to match API specification.

The response schema used here is also incorrect and should follow the same format as the actual Mailtrap Batch API.


562-574: Update transactional batch response schema to match API specification.

This test also uses the incorrect response schema format and needs to be aligned with the actual API.


376-388: ⚠️ Potential issue

Update API response schema to match Mailtrap Batch API specification.

The current test uses an incorrect response schema with success and responses array structure. According to the Mailtrap Batch API documentation, the actual response has a top-level response object containing batch details and a requestID string.

Apply this diff to correct the response schema:

-        const expectedBatchResponseData = {
-          success: true,
-          responses: [
-            {
-              success: true,
-              message_ids: ["57f17fe0-3935-11f0-0000-f15507b34198"],
-            },
-            {
-              success: true,
-              message_ids: ["57f17fe0-3935-11f0-0000-f15507b34199"],
-            },
-          ],
-        };
+        const expectedBatchResponseData = {
+          response: {
+            emailBatchID: expect.any(Number),
+            surveyID: expect.any(Number),
+            userID: expect.any(Number),
+            batchName: null,
+            subject: expect.any(String),
+            description: expect.any(String),
+            emailText: expect.any(String),
+            status: expect.any(Number),
+            batchType: expect.any(Number),
+            emailCount: 2,
+            emailFrom: expect.any(String),
+            creationDate: expect.any(String),
+            emailStatsList: null,
+            emailFromName: expect.any(String),
+            emailBatchStatistics: expect.any(Object),
+          },
+          requestID: expect.any(String),
+        };

626-634: ⚠️ Potential issue

Correct the error response schema for batch sending.

The error handling test uses an incorrect response structure. Based on the handleSendingError function analysis from past reviews, the API should return error responses with an errors object containing error arrays, not a success: true wrapper with individual response errors.

Apply this diff to correct the error response structure:

-        const responseData = {
-          success: true,
-          responses: [
-            {
-              success: false,
-              errors: ["'from' is required", "'subject' is required"],
-            },
-          ],
-        };
+        const responseData = {
+          errors: {
+            name: ["'from' is required", "'subject' is required"],
+          },
+        };
+        mock.onPost(endpoint).reply(400, responseData);

Also update the test expectations:

-        // @ts-ignore
-        const result = await batchClient.batchSend(batchData);
-        expect(result).toEqual(responseData);
-        expect(result.responses[0].success).toBe(false);
-        expect(result.responses[0].errors).toContain("'from' is required");
-        expect(result.responses[0].errors).toContain("'subject' is required");
+        try {
+          await batchClient.batchSend(batchData);
+        } catch (error) {
+          expect(error).toBeInstanceOf(MailtrapError);
+          if (error instanceof MailtrapError) {
+            expect(error.message).toEqual("'from' is required, 'subject' is required");
+          }
+        }
🧹 Nitpick comments (1)
src/__tests__/lib/mailtrap-client.test.ts (1)

653-654: Remove the @ts-ignore directive.

The @ts-ignore directive should be removed after correcting the error response handling logic in the previous comment.

-        // @ts-ignore
-        const result = await batchClient.batchSend(batchData);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 79484d4 and 018e75f.

📒 Files selected for processing (2)
  • src/__tests__/lib/mailtrap-client.test.ts (1 hunks)
  • src/lib/MailtrapClient.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/lib/MailtrapClient.ts
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/__tests__/lib/mailtrap-client.test.ts (1)
src/lib/MailtrapError.ts (1)
  • MailtrapError (1-1)
🔇 Additional comments (1)
src/__tests__/lib/mailtrap-client.test.ts (1)

331-660: Comprehensive test coverage implemented well.

The batch sending test suite provides excellent coverage of different scenarios including mode incompatibility, various sending modes (bulk, sandbox, transactional), template usage, and error handling. The test structure follows good patterns and the batch data structures are well-formed.

Comment on lines 155 to 156
base: preparedBase,
requests,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There can be text, html or attachments on both base AND single element from requests but for some reason we only encodeMailBuffers on base, why?

@narekhovhannisyan narekhovhannisyan merged commit 946ce71 into main May 30, 2025
4 checks passed
@narekhovhannisyan narekhovhannisyan deleted the batch-sending-api branch May 30, 2025 13:24
@vittorius vittorius mentioned this pull request Jul 8, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants