(params: BuildMimeMessageParams)
| 479 | } |
| 480 | |
| 481 | export function buildMimeMessage(params: BuildMimeMessageParams): string { |
| 482 | const { to, cc, bcc, subject, body, contentType, inReplyTo, references, attachments } = params |
| 483 | const messageParts: string[] = [] |
| 484 | const { plain, html } = buildBodyAlternatives(body, contentType) |
| 485 | |
| 486 | messageParts.push(`To: ${to}`) |
| 487 | if (cc) { |
| 488 | messageParts.push(`Cc: ${cc}`) |
| 489 | } |
| 490 | if (bcc) { |
| 491 | messageParts.push(`Bcc: ${bcc}`) |
| 492 | } |
| 493 | messageParts.push(`Subject: ${encodeRfc2047(subject || '')}`) |
| 494 | |
| 495 | if (inReplyTo) { |
| 496 | messageParts.push(`In-Reply-To: ${inReplyTo}`) |
| 497 | } |
| 498 | if (references) { |
| 499 | const referencesChain = inReplyTo ? `${references} ${inReplyTo}` : references |
| 500 | messageParts.push(`References: ${referencesChain}`) |
| 501 | } else if (inReplyTo) { |
| 502 | messageParts.push(`References: ${inReplyTo}`) |
| 503 | } |
| 504 | |
| 505 | messageParts.push('MIME-Version: 1.0') |
| 506 | |
| 507 | if (attachments && attachments.length > 0) { |
| 508 | const mixedBoundary = generateBoundary() |
| 509 | const altBoundary = generateBoundary() |
| 510 | |
| 511 | messageParts.push(`Content-Type: multipart/mixed; boundary="${mixedBoundary}"`) |
| 512 | messageParts.push('') |
| 513 | messageParts.push(`--${mixedBoundary}`) |
| 514 | messageParts.push(`Content-Type: multipart/alternative; boundary="${altBoundary}"`) |
| 515 | messageParts.push('') |
| 516 | messageParts.push(...renderAlternativeParts(plain, html, altBoundary)) |
| 517 | messageParts.push('') |
| 518 | |
| 519 | for (const attachment of attachments) { |
| 520 | messageParts.push(`--${mixedBoundary}`) |
| 521 | messageParts.push(`Content-Type: ${attachment.mimeType}`) |
| 522 | messageParts.push(`Content-Disposition: attachment; filename="${attachment.filename}"`) |
| 523 | messageParts.push('Content-Transfer-Encoding: base64') |
| 524 | messageParts.push('') |
| 525 | |
| 526 | const base64Content = attachment.content.toString('base64') |
| 527 | const lines = base64Content.match(/.{1,76}/g) || [] |
| 528 | messageParts.push(...lines) |
| 529 | messageParts.push('') |
| 530 | } |
| 531 | |
| 532 | messageParts.push(`--${mixedBoundary}--`) |
| 533 | } else { |
| 534 | const altBoundary = generateBoundary() |
| 535 | messageParts.push(`Content-Type: multipart/alternative; boundary="${altBoundary}"`) |
| 536 | messageParts.push('') |
| 537 | messageParts.push(...renderAlternativeParts(plain, html, altBoundary)) |
| 538 | } |
no test coverage detected