-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
204 lines (173 loc) · 5.16 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
module.exports = function (...args) {
const headers = [];
const plainPart = [];
const htmlPart = [];
const multiParts = [];
for (let index = 0; index < args.length; index++) {
const arg = args[index];
if (Array.isArray(arg)) {
// Flatten the args array to enable call sites without the spread operator
args.splice(index + 1, 0, ...arg);
continue;
}
if (typeof arg === 'string') {
// TODO: Split the line if too long and be aware of HTML tags
htmlPart.push(arg);
continue;
}
if (typeof arg === 'number') {
htmlPart.push(arg.toString());
continue;
}
if (arg instanceof Subject) {
// TODO: Split the subject line into multiple lines if too long
headers.push(`Subject: ${arg.subject}`);
continue;
}
// TODO: Split the sender(s) line into multiple lines if too long
if (arg instanceof Sender) {
if (arg.sender === arg.email) {
headers.push(`From: ${arg.sender}`);
}
else {
headers.push(`From: ${arg.sender} <${arg.email}>`);
}
continue;
}
// TODO: Split the recipient(s) line into multiple lines if too long
if (arg instanceof Recipient) {
if (arg.recipient === arg.email) {
headers.push(`To: ${arg.recipient}`);
}
else {
headers.push(`To: ${arg.recipient} <${arg.email}>`);
}
continue;
}
if (arg instanceof Inline) {
multiParts.push(arg);
continue;
}
throw new Error(`Invalid agument ${JSON.stringify(arg)}.`);
}
const eml = [];
// Generate the plain text version by stripping the HTML tags
let state = 'plain';
for (const htmlLine of htmlPart) {
let plainLine = '';
for (let index = 0; index < htmlLine.length; index++) {
const char = htmlLine[index];
switch (state) {
case 'plain': {
if (char === '<') {
state = 'html';
continue;
}
plainLine += char;
break;
}
case 'html': {
if (char === '>') {
state = 'plain';
continue;
}
break;
}
default: {
throw new Error(`Invalid state '${state}'.`);
}
}
}
// Ignore the line if it is completely HTML to avoid an extra line break
if (plainLine) {
// TODO: Split the line if it is too long
plainPart.push(plainLine);
}
}
// TODO: Ditch this and correctly include the plain text version as alternative
if (multiParts.length === 0) {
if (headers.length > 0) {
eml.push(...headers);
}
eml.push('Content-Type: text/html');
eml.push('');
eml.push(...htmlPart);
}
else {
if (headers.length > 0) {
eml.push(...headers);
}
eml.push('Content-Type: multipart/alternative;');
eml.push(' boudary=abcdefabcdefabcdefabcdefabcdef')
eml.push('');
eml.push('--abcdefabcdefabcdefabcdefabcdef');
eml.push('');
eml.push(...plainPart);
eml.push('');
eml.push('--abcdefabcdefabcdefabcdefabcdef');
eml.push('Content-Type: multipart/related');
eml.push(' boundary=fedcbafedcbafedcbafedcbafedcba');
eml.push('');
eml.push('--fedcbafedcbafedcbafedcbafedcba');
eml.push('Content-Type: text/html');
eml.push('');
eml.push(...htmlPart);
for (const part of multiParts) {
eml.push('');
eml.push('--fedcbafedcbafedcbafedcbafedcba');
eml.push(`Content-Id: ${part.name}@`);
eml.push(`Content-Disposition: inline; filename="${part.name}"`);
eml.push(`Content-Type: ${part.type}; name="${part.name}"`);
eml.push('Content-Transfer-Encoding: BASE64');
eml.push('');
eml.push(...part.buffer.toString('base64').match(/.{0,76}/g));
}
eml.push('');
eml.push('--fedcbafedcbafedcbafedcbafedcba--');
eml.push('');
eml.push('--abcdefabcdefabcdefabcdefabcdef--');
}
return eml;
};
class Subject {
constructor(subject) {
this.subject = subject;
}
}
module.exports.subject = function subject(subject) {
return new Subject(subject);
};
class Sender {
constructor(sender, email = sender) {
if (!email.includes('@') || !email.includes('.', email.indexOf('@'))) {
throw new Error('Invalid email address.');
}
this.sender = sender;
this.email = email;
}
}
module.exports.sender = function sender(sender, email) {
return new Sender(sender, email);
};
class Recipient {
constructor(recipient, email = recipient) {
if (!email.includes('@') || !email.includes('.', email.indexOf('@'))) {
throw new Error('Invalid email address.');
}
this.recipient = recipient;
this.email = email;
}
}
module.exports.recipient = function recipient(recipient, email) {
return new Recipient(recipient, email);
};
class Inline {
constructor(name, type, buffer) {
this.name = name;
this.type = type;
this.buffer = buffer;
}
}
module.exports.inline = function inline(name, type, buffer) {
return new Inline(name, type, buffer);
};