Skip to content

Commit 2becb56

Browse files
committed
feat(messages,drafts): support isPlaintext for messages.send and drafts.create
1 parent 7fe13ff commit 2becb56

File tree

5 files changed

+162
-1
lines changed

5 files changed

+162
-1
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
- Support `isPlaintext` boolean for messages send and drafts create requests
12+
1013
### Changed
1114
- Upgraded node-fetch from v2 to v3 for better ESM support and compatibility with edge environments
1215

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// @ts-ignore dotenv is installed in examples package
2+
import * as dotenv from 'dotenv';
3+
// @ts-ignore import from built SDK when running examples
4+
import Nylas, { SendMessageRequest } from 'nylas';
5+
import * as path from 'path';
6+
import * as process from 'process';
7+
8+
dotenv.config({ path: path.resolve(__dirname, '../../.env') });
9+
10+
async function main(): Promise<void> {
11+
const apiKey: string = process.env.NYLAS_API_KEY || '';
12+
const grantId: string = process.env.NYLAS_GRANT_ID || '';
13+
const toEmail: string | undefined = process.env.TEST_EMAIL;
14+
15+
if (!apiKey || !grantId || !toEmail) {
16+
console.error('Please set NYLAS_API_KEY, NYLAS_GRANT_ID, and TEST_EMAIL in examples/.env');
17+
process.exit(1);
18+
}
19+
20+
const nylas = new Nylas({
21+
apiKey,
22+
apiUri: process.env.NYLAS_API_URI || 'https://api.us.nylas.com',
23+
});
24+
25+
const requestBody: SendMessageRequest = {
26+
to: [{ name: 'Plaintext Recipient', email: toEmail }],
27+
subject: 'Plaintext message example',
28+
body: 'This message is sent as plain text only.',
29+
isPlaintext: true,
30+
};
31+
32+
const res = await nylas.messages.send({ identifier: grantId, requestBody });
33+
console.log('Sent message id:', res.data.id);
34+
}
35+
36+
if (require.main === module) {
37+
main();
38+
}
39+
40+

src/models/drafts.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ export interface CreateDraftRequest {
7171
* An array of custom headers to add to the message.
7272
*/
7373
customHeaders?: CustomHeader[];
74+
/**
75+
* When true, the message body is sent as plain text and the MIME data doesn't include the HTML version of the message.
76+
* When false, the message body is sent as HTML. Defaults to false.
77+
*/
78+
isPlaintext?: boolean;
7479
}
7580

7681
/**
@@ -103,7 +108,10 @@ export interface Draft
103108
/**
104109
* Interface representing a request to update a draft.
105110
*/
106-
export type UpdateDraftRequest = Partial<CreateDraftRequest> & {
111+
export type UpdateDraftRequest = Omit<
112+
Partial<CreateDraftRequest>,
113+
'isPlaintext'
114+
> & {
107115
/**
108116
* Return drafts that are unread.
109117
*/

tests/resources/drafts.spec.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,61 @@ describe('Drafts', () => {
377377
expect(capturedRequest.method).toEqual('POST');
378378
expect(capturedRequest.path).toEqual('/v3/grants/id123/drafts');
379379
});
380+
381+
it('should include isPlaintext in JSON body when provided for create', async () => {
382+
const jsonBody = {
383+
to: [{ name: 'Test', email: 'test@example.com' }],
384+
subject: 'Plain text draft',
385+
body: 'Hello world',
386+
isPlaintext: true,
387+
};
388+
389+
await drafts.create({
390+
identifier: 'id123',
391+
requestBody: jsonBody,
392+
});
393+
394+
const capturedRequest = apiClient.request.mock.calls[0][0];
395+
expect(capturedRequest.method).toEqual('POST');
396+
expect(capturedRequest.path).toEqual('/v3/grants/id123/drafts');
397+
expect(capturedRequest.body).toEqual(jsonBody);
398+
});
399+
400+
it('should include isPlaintext in multipart form message when provided for create', async () => {
401+
const messageJson = {
402+
to: [{ name: 'Test', email: 'test@example.com' }],
403+
subject: 'Plain text draft',
404+
body: 'Hello world',
405+
isPlaintext: true,
406+
};
407+
const fileStream = createReadableStream('This is the text from file 1');
408+
const file1: CreateAttachmentRequest = {
409+
filename: 'file1.txt',
410+
contentType: 'text/plain',
411+
content: fileStream,
412+
size: 3 * 1024 * 1024,
413+
};
414+
415+
await drafts.create({
416+
identifier: 'id123',
417+
requestBody: {
418+
...messageJson,
419+
attachments: [file1],
420+
},
421+
});
422+
423+
const capturedRequest = apiClient.request.mock.calls[0][0];
424+
const formData = (
425+
capturedRequest.form as any as MockedFormData
426+
)._getAppendedData();
427+
const parsed = JSON.parse(formData.message);
428+
expect(parsed.to).toEqual(messageJson.to);
429+
expect(parsed.subject).toEqual(messageJson.subject);
430+
expect(parsed.body).toEqual(messageJson.body);
431+
expect(parsed.is_plaintext).toBe(true);
432+
expect(capturedRequest.method).toEqual('POST');
433+
expect(capturedRequest.path).toEqual('/v3/grants/id123/drafts');
434+
});
380435
});
381436

382437
describe('update', () => {

tests/resources/messages.spec.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,61 @@ describe('Messages', () => {
509509
expect(capturedRequest.method).toEqual('POST');
510510
expect(capturedRequest.path).toEqual('/v3/grants/id123/messages/send');
511511
});
512+
513+
it('should include isPlaintext in JSON body when provided', async () => {
514+
const jsonBody = {
515+
to: [{ name: 'Test', email: 'test@example.com' }],
516+
subject: 'Plain text email',
517+
body: 'Hello world',
518+
isPlaintext: true,
519+
};
520+
521+
await messages.send({
522+
identifier: 'id123',
523+
requestBody: jsonBody,
524+
});
525+
526+
const capturedRequest = apiClient.request.mock.calls[0][0];
527+
expect(capturedRequest.method).toEqual('POST');
528+
expect(capturedRequest.path).toEqual('/v3/grants/id123/messages/send');
529+
expect(capturedRequest.body).toEqual(jsonBody);
530+
});
531+
532+
it('should include isPlaintext in multipart form message when provided', async () => {
533+
const messageJson = {
534+
to: [{ name: 'Test', email: 'test@example.com' }],
535+
subject: 'Plain text email',
536+
body: 'Hello world',
537+
isPlaintext: true,
538+
};
539+
const fileStream = createReadableStream('This is the text from file 1');
540+
const file1: CreateAttachmentRequest = {
541+
filename: 'file1.txt',
542+
contentType: 'text/plain',
543+
content: fileStream,
544+
size: 3 * 1024 * 1024,
545+
};
546+
547+
await messages.send({
548+
identifier: 'id123',
549+
requestBody: {
550+
...messageJson,
551+
attachments: [file1],
552+
},
553+
});
554+
555+
const capturedRequest = apiClient.request.mock.calls[0][0];
556+
const formData = (
557+
capturedRequest.form as any as MockedFormData
558+
)._getAppendedData();
559+
const parsed = JSON.parse(formData.message);
560+
expect(parsed.to).toEqual(messageJson.to);
561+
expect(parsed.subject).toEqual(messageJson.subject);
562+
expect(parsed.body).toEqual(messageJson.body);
563+
expect(parsed.is_plaintext).toBe(true);
564+
expect(capturedRequest.method).toEqual('POST');
565+
expect(capturedRequest.path).toEqual('/v3/grants/id123/messages/send');
566+
});
512567
});
513568

514569
describe('scheduledMessages', () => {

0 commit comments

Comments
 (0)