You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Optional `dkim.headerFieldNames` lists which message headers are included in the DKIM `h=` tag (use lowercase names). If you omit it, the default set is `from`, `to`, `subject`, `date`, `message-id`, `mime-version`, `content-type`.
With `secure: false`, the client opens a plain TCP connection, sends `EHLO`, then:
137
+
138
+
- If the server advertises `STARTTLS`, the client upgrades to TLS and sends `EHLO` again (this applies to any port where the server offers `STARTTLS`, not only 587).
139
+
- On **port 587**, the server **must** advertise `STARTTLS`. If it does not, the client throws an error.
140
+
141
+
With `secure: true`, the connection uses TLS from the first byte (typical for port 465).
142
+
132
143
```ts
133
-
// Port 587 with STARTTLS upgrade.
144
+
// Port 587: plain connect, then mandatory STARTTLS upgrade after EHLO.
134
145
{
135
146
host: 'smtp.gmail.com',
136
147
port: 587,
137
148
secure: false
138
149
}
139
150
140
-
// Port 465 with direct TLS.
151
+
// Port 465: TLS from connect.
141
152
{
142
153
host: 'smtp.gmail.com',
143
154
port: 465,
@@ -221,6 +232,18 @@ await transporter.send({
221
232
222
233
## Advanced Features
223
234
235
+
### Combining Body Modes
236
+
237
+
The formatter builds **one** MIME structure per message. It does **not** combine embedded images, calendar parts, and file attachments into a single custom multipart tree. Evaluation order is:
238
+
239
+
1.`embeddedImages` → multipart/related (with HTML and related parts)
240
+
2. Else `calendarEvent` → multipart/alternative including the calendar
241
+
3. Else `attachments` → multipart/mixed
242
+
4. Else `html` and `text` together → multipart/alternative
243
+
5. Else `html` only, or plain `text` only
244
+
245
+
If you set more than one of `embeddedImages`, `calendarEvent`, and `attachments`, the earlier branch wins and the others are ignored for structure (for example calendar plus attachments in one send is not supported as one merged layout).
246
+
224
247
### File Attachments
225
248
226
249
```ts
@@ -243,6 +266,12 @@ await transporter.send({
243
266
244
267
### Attachment Encoding Options
245
268
269
+
Transfer encoding behavior:
270
+
271
+
-**`base64`:** Pass **raw** content (`string` as UTF-8 text, or `Uint8Array` as bytes). The library encodes to Base64. Do **not** pass a string that is already Base64 unless you want it encoded again (wrong for binary files).
272
+
-**`7bit`:** Content must be **ASCII only** (bytes 0–127). Non-ASCII input throws.
273
+
-**`quoted-printable`:** Bytes are escaped per quoted-printable rules. The encoder does **not** fold lines to ~76 characters, which some strict MTAs expect for long lines.
274
+
246
275
```ts
247
276
// Use base64, 7bit, or quoted-printable transfer encoding.
248
277
awaittransporter.send({
@@ -253,7 +282,7 @@ await transporter.send({
253
282
attachments: [
254
283
{
255
284
filename: 'base64.txt',
256
-
content: fileBase64Content,
285
+
content: rawFileContent,
257
286
contentType: 'text/plain',
258
287
encoding: 'base64'
259
288
},
@@ -414,6 +443,12 @@ await transporter.send({
414
443
})
415
444
```
416
445
446
+
Rules:
447
+
448
+
- Header **names** must match token characters (see RFC 5322 `atext`-style set used in code). Empty names are rejected.
449
+
- Names and values must **not** contain CR or LF.
450
+
- These names are **reserved** and cannot be set via `headers` (the library owns them): `bcc`, `cc`, `content-disposition`, `content-id`, `content-transfer-encoding`, `content-type`, `date`, `from`, `message-id`, `mime-version`, `reply-to`, `subject`, `to`.
451
+
417
452
## API Reference
418
453
419
454
### Main API
@@ -441,6 +476,7 @@ await transporter.send({
441
476
|`dkim.domainName`| string | no | DKIM signing domain |`'example.com'`|
442
477
|`dkim.keySelector`| string | no | DKIM DNS selector |`'mail'`|
|`dkim.headerFieldNames`| string[]| no | Headers in DKIM `h=` list |`['from','to','subject',...]`|
444
480
445
481
### Message Properties
446
482
@@ -459,12 +495,11 @@ await transporter.send({
459
495
|`calendarEvent`| object | no | Calendar invitation |
460
496
|`headers`| object | no | Custom email headers |
461
497
462
-
Attachment and embedded image encoding supports `base64`, `7bit`, and `quoted-printable`.
463
-
Embedded image disposition supports `inline` and `attachment`.
498
+
Attachment and embedded image `encoding` supports `base64` (library encodes raw content), `7bit` (ASCII only), and `quoted-printable` (no automatic line folding). Embedded image `disposition` supports `inline` and `attachment`.
464
499
465
500
### Send Result
466
501
467
-
`transporter.send()`now resolves a structured result:
502
+
`transporter.send()` resolves a structured result:
Many failures surface as `Error` messages prefixed with `Failed to send message:` or `SMTP connection failed:` plus the underlying reason. Simple `message.includes('…')` checks can miss cases if the wording changes, so prefer logging the full message or matching a broader substring.
513
+
477
514
```ts
478
515
// Catch transport or SMTP response errors.
479
516
try {
480
517
awaittransporter.send(message)
481
518
} catch (error) {
482
-
console.error('Email failed:', error.message)
483
-
if (error.message.includes('authentication')) {
519
+
const text =errorinstanceofError?error.message:String(error)
0 commit comments