1
0
mirror of https://github.com/eleith/emailjs.git synced 2024-06-25 16:29:04 +00:00
emailjs/test/message.ts

456 lines
12 KiB
TypeScript
Raw Normal View History

2022-04-14 18:30:25 +00:00
import { createReadStream, readFileSync } from 'fs';
2022-04-14 19:22:31 +00:00
import { URL } from 'url';
2020-05-27 12:49:21 +00:00
2020-07-27 08:58:28 +00:00
import test from 'ava';
2022-03-20 10:04:04 +00:00
import { simpleParser } from 'mailparser';
import type { AddressObject, ParsedMail } from 'mailparser';
2020-05-27 12:49:21 +00:00
import { SMTPServer } from 'smtp-server';
2020-04-21 03:20:42 +00:00
import { SMTPClient, Message } from '../email.js';
import type { MessageAttachment, MessageHeaders } from '../email.js';
2021-08-28 18:54:08 +00:00
2022-04-14 18:02:41 +00:00
const textFixtureUrl = new URL('attachments/smtp.txt', import.meta.url);
2022-04-14 18:30:25 +00:00
const textFixture = readFileSync(textFixtureUrl, 'utf-8');
2022-04-14 18:02:41 +00:00
const htmlFixtureUrl = new URL('attachments/smtp.html', import.meta.url);
2022-04-14 18:30:25 +00:00
const htmlFixture = readFileSync(htmlFixtureUrl, 'utf-8');
2022-04-14 18:02:41 +00:00
const pdfFixtureUrl = new URL('attachments/smtp.pdf', import.meta.url);
2022-04-14 18:30:25 +00:00
const pdfFixture = readFileSync(pdfFixtureUrl, 'base64');
2022-04-14 18:02:41 +00:00
const tarFixtureUrl = new URL(
'attachments/postfix-2.8.7.tar.gz',
import.meta.url
);
2022-04-14 18:30:25 +00:00
const tarFixture = readFileSync(tarFixtureUrl, 'base64');
2022-04-14 18:02:41 +00:00
2021-06-26 19:23:26 +00:00
/**
* \@types/mailparser@3.0.2 breaks our code
* @see https://github.com/DefinitelyTyped/DefinitelyTyped/pull/50744
*/
type ParsedMailCompat = Omit<ParsedMail, 'to'> & { to?: AddressObject };
2022-03-03 23:44:35 +00:00
const port = 5555;
2021-06-26 19:23:26 +00:00
const parseMap = new Map<string, ParsedMailCompat>();
const client = new SMTPClient({
port,
user: 'pooh',
password: 'honey',
ssl: true,
});
const server = new SMTPServer({
secure: true,
onAuth(auth, _session, callback) {
if (auth.username == 'pooh' && auth.password == 'honey') {
callback(null, { user: 'pooh' });
} else {
return callback(new Error('invalid user / pass'));
}
},
2020-07-27 08:58:28 +00:00
async onData(stream, _session, callback: () => void) {
2021-06-26 19:23:26 +00:00
const mail = (await simpleParser(stream, {
skipHtmlToText: true,
skipTextToHtml: true,
skipImageLinks: true,
2021-06-26 19:23:26 +00:00
} as Record<string, unknown>)) as ParsedMailCompat;
2020-07-27 08:58:28 +00:00
parseMap.set(mail.subject as string, mail);
callback();
2020-07-27 08:58:28 +00:00
},
});
function send(headers: Partial<MessageHeaders>) {
2021-06-26 19:23:26 +00:00
return new Promise<ParsedMailCompat>((resolve, reject) => {
2020-07-27 08:58:28 +00:00
client.send(new Message(headers), (err) => {
if (err) {
reject(err);
} else {
2021-06-26 19:23:26 +00:00
resolve(parseMap.get(headers.subject as string) as ParsedMailCompat);
2020-07-27 08:58:28 +00:00
}
});
});
}
2020-07-27 06:38:36 +00:00
test.before(async (t) => {
server.listen(port, t.pass);
});
2020-07-27 09:10:34 +00:00
test.after(async (t) => {
server.close(t.pass);
});
2020-07-27 06:38:36 +00:00
2020-07-27 08:58:28 +00:00
test('simple text message', async (t) => {
2020-04-21 03:20:42 +00:00
const msg = {
subject: 'this is a test TEXT message from emailjs',
from: 'zelda@gmail.com',
to: 'gannon@gmail.com',
cc: 'gannon@gmail.com',
bcc: 'gannon@gmail.com',
2020-04-21 03:20:42 +00:00
text: 'hello friend, i hope this message finds you well.',
'message-id': 'this is a special id',
};
2020-07-27 08:58:28 +00:00
const mail = await send(msg);
t.is(mail.text, msg.text + '\n\n\n');
t.is(mail.subject, msg.subject);
t.is(mail.from?.text, msg.from);
t.is(mail.to?.text, msg.to);
t.is(mail.messageId, '<' + msg['message-id'] + '>');
2020-04-21 03:20:42 +00:00
});
2020-07-27 08:58:28 +00:00
test('null text message', async (t) => {
2020-04-21 03:20:42 +00:00
const msg = {
subject: 'this is a test TEXT message from emailjs',
from: 'zelda@gmail.com',
to: 'gannon@gmail.com',
text: null,
'message-id': 'this is a special id',
};
2020-07-27 08:58:28 +00:00
const mail = await send(msg);
t.is(mail.text, '\n\n\n');
2020-04-21 03:20:42 +00:00
});
2020-07-27 08:58:28 +00:00
test('empty text message', async (t) => {
2020-04-21 03:20:42 +00:00
const msg = {
subject: 'this is a test TEXT message from emailjs',
from: 'zelda@gmail.com',
to: 'gannon@gmail.com',
text: '',
'message-id': 'this is a special id',
};
2020-07-27 08:58:28 +00:00
const mail = await send(msg);
t.is(mail.text, '\n\n\n');
2020-04-21 03:20:42 +00:00
});
2020-07-27 08:58:28 +00:00
test('simple unicode text message', async (t) => {
2020-04-21 03:20:42 +00:00
const msg = {
subject: 'this ✓ is a test ✓ TEXT message from emailjs',
from: 'zelda✓ <zelda@gmail.com>',
to: 'gannon✓ <gannon@gmail.com>',
text: 'hello ✓ friend, i hope this message finds you well.',
};
2020-07-27 08:58:28 +00:00
const mail = await send(msg);
t.is(mail.text, msg.text + '\n\n\n');
t.is(mail.subject, msg.subject);
t.is(mail.from?.text, msg.from);
t.is(mail.to?.text, msg.to);
2020-04-21 03:20:42 +00:00
});
2020-07-27 08:58:28 +00:00
test('very large text message', async (t) => {
2020-04-21 03:20:42 +00:00
// thanks to jart+loberstech for this one!
const msg = {
subject: 'this is a test TEXT message from emailjs',
from: 'ninjas@gmail.com',
to: 'pirates@gmail.com',
2022-04-14 18:02:41 +00:00
text: textFixture,
2020-04-21 03:20:42 +00:00
};
2020-07-27 08:58:28 +00:00
const mail = await send(msg);
t.is(mail.text, msg.text.replace(/\r/g, '') + '\n\n\n');
t.is(mail.subject, msg.subject);
t.is(mail.from?.text, msg.from);
t.is(mail.to?.text, msg.to);
2020-04-21 03:20:42 +00:00
});
2020-07-27 08:58:28 +00:00
test('very large text data message', async (t) => {
2022-04-14 18:02:41 +00:00
const text = '<html><body><pre>' + textFixture + '</pre></body></html>';
2020-04-21 03:20:42 +00:00
const msg = {
subject: 'this is a test TEXT+DATA message from emailjs',
from: 'lobsters@gmail.com',
to: 'lizards@gmail.com',
2021-05-20 15:18:15 +00:00
text: 'hello friend if you are seeing this, you can not view html emails. it is attached inline.',
attachment: {
2020-04-23 04:26:49 +00:00
data: text,
alternative: true,
},
2020-04-21 03:20:42 +00:00
};
2020-07-27 08:58:28 +00:00
const mail = await send(msg);
t.is(mail.html, text.replace(/\r/g, ''));
t.is(mail.text, msg.text + '\n');
t.is(mail.subject, msg.subject);
t.is(mail.from?.text, msg.from);
t.is(mail.to?.text, msg.to);
2020-04-21 03:20:42 +00:00
});
2020-07-27 08:58:28 +00:00
test('html data message', async (t) => {
2020-04-21 03:20:42 +00:00
const msg = {
subject: 'this is a test TEXT+HTML+DATA message from emailjs',
from: 'obama@gmail.com',
to: 'mitt@gmail.com',
attachment: {
2022-04-14 18:02:41 +00:00
data: htmlFixture,
2020-04-23 04:26:49 +00:00
alternative: true,
},
2020-04-21 03:20:42 +00:00
};
2020-07-27 08:58:28 +00:00
const mail = await send(msg);
2022-04-14 18:02:41 +00:00
t.is(mail.html, htmlFixture.replace(/\r/g, ''));
2020-07-27 08:58:28 +00:00
t.is(mail.text, '\n');
t.is(mail.subject, msg.subject);
t.is(mail.from?.text, msg.from);
t.is(mail.to?.text, msg.to);
2020-04-21 03:20:42 +00:00
});
2020-07-27 08:58:28 +00:00
test('html file message', async (t) => {
2020-04-21 03:20:42 +00:00
const msg = {
subject: 'this is a test TEXT+HTML+FILE message from emailjs',
from: 'thomas@gmail.com',
to: 'nikolas@gmail.com',
attachment: {
path: new URL('attachments/smtp.html', import.meta.url),
2020-04-23 04:26:49 +00:00
alternative: true,
},
2020-04-21 03:20:42 +00:00
};
2020-07-27 08:58:28 +00:00
const mail = await send(msg);
2022-04-14 18:02:41 +00:00
t.is(mail.html, htmlFixture.replace(/\r/g, ''));
2020-07-27 08:58:28 +00:00
t.is(mail.text, '\n');
t.is(mail.subject, msg.subject);
t.is(mail.from?.text, msg.from);
t.is(mail.to?.text, msg.to);
2020-04-21 03:20:42 +00:00
});
2020-07-27 08:58:28 +00:00
test('html with image embed message', async (t) => {
2022-04-14 18:30:25 +00:00
const htmlFixture2Url = new URL('attachments/smtp2.html', import.meta.url);
const imageFixtureUrl = new URL('attachments/smtp.gif', import.meta.url);
2020-04-21 03:20:42 +00:00
const msg = {
subject: 'this is a test TEXT+HTML+IMAGE message from emailjs',
from: 'ninja@gmail.com',
to: 'pirate@gmail.com',
attachment: {
2022-04-14 18:30:25 +00:00
path: htmlFixture2Url,
2020-04-21 03:20:42 +00:00
alternative: true,
related: [
{
2022-04-14 18:30:25 +00:00
path: imageFixtureUrl,
2020-04-21 03:20:42 +00:00
type: 'image/gif',
name: 'smtp-diagram.gif',
headers: { 'Content-ID': '<smtp-diagram@local>' },
},
],
},
2020-04-21 03:20:42 +00:00
};
2020-07-27 08:58:28 +00:00
const mail = await send(msg);
t.is(
mail.attachments[0].content.toString('base64'),
2022-04-14 18:30:25 +00:00
readFileSync(imageFixtureUrl, 'base64')
2020-07-27 08:58:28 +00:00
);
2022-04-14 18:30:25 +00:00
t.is(mail.html, readFileSync(htmlFixture2Url, 'utf-8').replace(/\r/g, ''));
2020-07-27 08:58:28 +00:00
t.is(mail.text, '\n');
t.is(mail.subject, msg.subject);
t.is(mail.from?.text, msg.from);
t.is(mail.to?.text, msg.to);
2020-04-21 03:20:42 +00:00
});
2020-07-27 08:58:28 +00:00
test('html data and attachment message', async (t) => {
2020-04-21 03:20:42 +00:00
const msg = {
subject: 'this is a test TEXT+HTML+FILE message from emailjs',
from: 'thomas@gmail.com',
to: 'nikolas@gmail.com',
attachment: [
{
path: new URL('attachments/smtp.html', import.meta.url),
alternative: true,
},
{ path: new URL('attachments/smtp.gif', import.meta.url) },
2020-05-27 12:34:05 +00:00
] as MessageAttachment[],
2020-04-21 03:20:42 +00:00
};
2020-07-27 08:58:28 +00:00
const mail = await send(msg);
2022-04-14 18:02:41 +00:00
t.is(mail.html, htmlFixture.replace(/\r/g, ''));
2020-07-27 08:58:28 +00:00
t.is(mail.text, '\n');
t.is(mail.subject, msg.subject);
t.is(mail.from?.text, msg.from);
t.is(mail.to?.text, msg.to);
2020-04-21 03:20:42 +00:00
});
2020-07-27 08:58:28 +00:00
test('attachment message', async (t) => {
2020-04-21 03:20:42 +00:00
const msg = {
subject: 'this is a test TEXT+ATTACHMENT message from emailjs',
from: 'washing@gmail.com',
to: 'lincoln@gmail.com',
text: 'hello friend, i hope this message and pdf finds you well.',
attachment: {
2022-04-14 18:02:41 +00:00
path: pdfFixtureUrl,
2020-04-21 03:20:42 +00:00
type: 'application/pdf',
name: 'smtp-info.pdf',
2020-05-27 12:34:05 +00:00
} as MessageAttachment,
2020-04-21 03:20:42 +00:00
};
2020-07-27 08:58:28 +00:00
const mail = await send(msg);
2022-04-14 18:02:41 +00:00
t.is(mail.attachments[0].content.toString('base64'), pdfFixture);
2020-07-27 08:58:28 +00:00
t.is(mail.text, msg.text + '\n');
t.is(mail.subject, msg.subject);
t.is(mail.from?.text, msg.from);
t.is(mail.to?.text, msg.to);
2020-04-21 03:20:42 +00:00
});
2020-07-27 08:58:28 +00:00
test('attachment sent with unicode filename message', async (t) => {
2020-04-21 03:20:42 +00:00
const msg = {
subject: 'this is a test TEXT+ATTACHMENT message from emailjs',
from: 'washing@gmail.com',
to: 'lincoln@gmail.com',
text: 'hello friend, i hope this message and pdf finds you well.',
attachment: {
2022-04-14 18:02:41 +00:00
path: pdfFixtureUrl,
2020-04-21 03:20:42 +00:00
type: 'application/pdf',
name: 'smtp-✓-info.pdf',
2020-05-27 12:34:05 +00:00
} as MessageAttachment,
2020-04-21 03:20:42 +00:00
};
2020-07-27 08:58:28 +00:00
const mail = await send(msg);
2022-04-14 18:02:41 +00:00
t.is(mail.attachments[0].content.toString('base64'), pdfFixture);
2020-07-27 08:58:28 +00:00
t.is(mail.attachments[0].filename, 'smtp-✓-info.pdf');
t.is(mail.text, msg.text + '\n');
t.is(mail.subject, msg.subject);
t.is(mail.from?.text, msg.from);
t.is(mail.to?.text, msg.to);
2020-04-21 03:20:42 +00:00
});
2020-07-27 08:58:28 +00:00
test('attachments message', async (t) => {
2020-04-21 03:20:42 +00:00
const msg = {
subject: 'this is a test TEXT+2+ATTACHMENTS message from emailjs',
from: 'sergey@gmail.com',
to: 'jobs@gmail.com',
text: 'hello friend, i hope this message and attachments finds you well.',
attachment: [
{
2022-04-14 18:02:41 +00:00
path: pdfFixtureUrl,
2020-04-21 03:20:42 +00:00
type: 'application/pdf',
name: 'smtp-info.pdf',
},
{
2022-04-14 18:02:41 +00:00
path: tarFixtureUrl,
2020-04-21 03:20:42 +00:00
type: 'application/tar-gz',
name: 'postfix.source.2.8.7.tar.gz',
},
2020-05-27 12:34:05 +00:00
] as MessageAttachment[],
2020-04-21 03:20:42 +00:00
};
2020-07-27 08:58:28 +00:00
const mail = await send(msg);
2022-04-14 18:02:41 +00:00
t.is(mail.attachments[0].content.toString('base64'), pdfFixture);
t.is(mail.attachments[1].content.toString('base64'), tarFixture);
2020-07-27 08:58:28 +00:00
t.is(mail.text, msg.text + '\n');
t.is(mail.subject, msg.subject);
t.is(mail.from?.text, msg.from);
t.is(mail.to?.text, msg.to);
2020-04-21 03:20:42 +00:00
});
2020-07-27 08:58:28 +00:00
test('streams message', async (t) => {
2020-04-21 03:20:42 +00:00
const msg = {
2020-04-23 04:26:49 +00:00
subject: 'this is a test TEXT+2+STREAMED+ATTACHMENTS message from emailjs',
2020-04-21 03:20:42 +00:00
from: 'stanford@gmail.com',
to: 'mit@gmail.com',
2021-05-20 15:18:15 +00:00
text: 'hello friend, i hope this message and streamed attachments finds you well.',
attachment: [
2020-04-23 04:26:49 +00:00
{
2022-04-14 18:02:41 +00:00
stream: createReadStream(pdfFixtureUrl),
type: 'application/pdf',
name: 'smtp-info.pdf',
},
{
stream: createReadStream(tarFixtureUrl),
2020-04-23 04:26:49 +00:00
type: 'application/x-gzip',
name: 'postfix.source.2.8.7.tar.gz',
},
],
2020-04-21 03:20:42 +00:00
};
2022-04-14 18:02:41 +00:00
for (const { stream } of msg.attachment) {
stream.pause();
}
2020-04-21 03:20:42 +00:00
2020-07-27 08:58:28 +00:00
const mail = await send(msg);
2022-04-14 18:02:41 +00:00
t.is(mail.attachments[0].content.toString('base64'), pdfFixture);
t.is(mail.attachments[1].content.toString('base64'), tarFixture);
2020-07-27 08:58:28 +00:00
t.is(mail.text, msg.text + '\n');
t.is(mail.subject, msg.subject);
t.is(mail.from?.text, msg.from);
t.is(mail.to?.text, msg.to);
2020-04-21 03:20:42 +00:00
});
2020-07-27 08:58:28 +00:00
test('message validation fails without `from` header', async (t) => {
const msg = new Message({});
const { isValid, validationError } = msg.checkValidity();
t.false(isValid);
t.is(validationError, 'Message must have a `from` header');
2020-07-27 08:58:28 +00:00
});
test('message validation fails without `to`, `cc`, or `bcc` header', async (t) => {
const { isValid, validationError } = new Message({
from: 'piglet@gmail.com',
}).checkValidity();
t.false(isValid);
t.is(
validationError,
'Message must have at least one `to`, `cc`, or `bcc` header'
2020-07-27 08:58:28 +00:00
);
});
2020-07-27 08:58:28 +00:00
test('message validation succeeds with only `to` recipient header (string)', async (t) => {
const { isValid, validationError } = new Message({
from: 'piglet@gmail.com',
2020-07-27 08:58:28 +00:00
to: 'pooh@gmail.com',
}).checkValidity();
t.true(isValid);
t.is(validationError, undefined);
});
2020-07-27 08:58:28 +00:00
test('message validation succeeds with only `to` recipient header (array)', async (t) => {
const { isValid, validationError } = new Message({
2020-07-27 08:58:28 +00:00
from: 'piglet@gmail.com',
to: ['pooh@gmail.com'],
}).checkValidity();
t.true(isValid);
t.is(validationError, undefined);
2020-07-27 08:58:28 +00:00
});
2020-07-27 08:58:28 +00:00
test('message validation succeeds with only `cc` recipient header (string)', async (t) => {
const { isValid, validationError } = new Message({
2020-07-27 08:58:28 +00:00
from: 'piglet@gmail.com',
cc: 'pooh@gmail.com',
}).checkValidity();
t.true(isValid);
t.is(validationError, undefined);
2020-07-27 08:58:28 +00:00
});
2020-07-27 08:58:28 +00:00
test('message validation succeeds with only `cc` recipient header (array)', async (t) => {
const { isValid, validationError } = new Message({
2020-07-27 08:58:28 +00:00
from: 'piglet@gmail.com',
cc: ['pooh@gmail.com'],
}).checkValidity();
t.true(isValid);
t.is(validationError, undefined);
2020-07-27 08:58:28 +00:00
});
2020-07-27 08:58:28 +00:00
test('message validation succeeds with only `bcc` recipient header (string)', async (t) => {
const { isValid, validationError } = new Message({
2020-07-27 08:58:28 +00:00
from: 'piglet@gmail.com',
bcc: 'pooh@gmail.com',
}).checkValidity();
t.true(isValid);
t.is(validationError, undefined);
2020-07-27 08:58:28 +00:00
});
2020-07-27 08:58:28 +00:00
test('message validation succeeds with only `bcc` recipient header (array)', async (t) => {
const { isValid, validationError } = new Message({
2020-07-27 08:58:28 +00:00
from: 'piglet@gmail.com',
bcc: ['pooh@gmail.com'],
}).checkValidity();
t.true(isValid);
t.is(validationError, undefined);
2020-07-27 08:58:28 +00:00
});