From c44987f1b90da76689f87d218b47cd1595628de5 Mon Sep 17 00:00:00 2001 From: Bjarn Bronsveld Date: Tue, 7 Oct 2025 21:37:00 +0200 Subject: [PATCH] feat: add support for inline attachments in email requests - Extended `attach` method to support optional `content_id` for inline attachments. - Updated tests to verify content_id functionality. - Updated README with documentation and examples for inline attachments. --- README.md | 3 ++- src/endpoints/email.spec.ts | 22 ++++++++++++++++++++++ src/endpoints/email.ts | 9 ++++++++- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f9abc13..8681bce 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,7 @@ const response = await lettermint.email 'X-Custom-Header': 'Custom Value', }) .attach('attachment.txt', Buffer.from('Hello World').toString('base64')) + .attach('logo.png', Buffer.from('...').toString('base64'), 'logo') // Inline attachment .idempotencyKey('unique-id-123') .metadata({ foo: 'bar', @@ -90,7 +91,7 @@ Methods for sending emails: - `bcc(...emails: string[])`: Set one or more BCC email addresses - `replyTo(...emails: string[])`: Set one or more Reply-To email addresses - `headers(headers: Record)`: Set custom headers for the email -- `attach(filename: string, base64Content: string)`: Attach a file to the email +- `attach(filename: string, base64Content: string, content_id?: string)`: Attach a file to the email. Optional `content_id` for inline attachments. - `route(route: string)`: Set the routing key for the email - `idempotencyKey(key: string)`: Set an idempotency key to prevent duplicate email sends - `metadata(metadata: Record)`: Set metadata for the email diff --git a/src/endpoints/email.spec.ts b/src/endpoints/email.spec.ts index 7cbb76b..9fb66fe 100644 --- a/src/endpoints/email.spec.ts +++ b/src/endpoints/email.spec.ts @@ -187,6 +187,28 @@ describe('EmailEndpoint', () => { }); }); + it('should add attachments with content_id', () => { + const result = emailEndpoint.attach('image.png', 'base64imagedata', 'logo'); + + expect(result).toBe(emailEndpoint); + + return emailEndpoint.send().then(() => { + expect(client.post).toHaveBeenCalledWith( + '/send', + expect.objectContaining({ + attachments: [ + { + filename: 'image.png', + content: 'base64imagedata', + content_id: 'logo', + }, + ], + }), + undefined + ); + }); + }); + it('should set the route', () => { const result = emailEndpoint.route('test-route'); diff --git a/src/endpoints/email.ts b/src/endpoints/email.ts index fdf1d4c..a55a0f3 100644 --- a/src/endpoints/email.ts +++ b/src/endpoints/email.ts @@ -13,6 +13,11 @@ export interface EmailAttachment { * The base64-encoded content of the attachment */ content: string; + + /** + * The Content-ID for inline attachments (optional) + */ + content_id?: string; } /** @@ -279,9 +284,10 @@ export class EmailEndpoint extends Endpoint { * * @param filename The attachment filename * @param content The base64-encoded file content + * @param content_id The Content-ID for inline attachments (optional) * @returns The current instance for chaining */ - public attach(filename: string, content: string): this { + public attach(filename: string, content: string, content_id?: string): this { if (!this.payload.attachments) { this.payload.attachments = []; } @@ -289,6 +295,7 @@ export class EmailEndpoint extends Endpoint { this.payload.attachments.push({ filename, content, + ...(content_id && { content_id }), }); return this;