ComposeMultipartMessage builds an RFC 2822 multipart/alternative email with text and HTML parts. If htmlBody is empty, falls back to a single text/plain message via ComposeMessage. See ComposeMessage for replyToMsgID / references semantics.
(from string, to []string, cc []string, subject, textBody, htmlBody, replyToMsgID string, references []string, fromDomain, replyTo, conversationID string)
| 74 | // If htmlBody is empty, falls back to a single text/plain message via ComposeMessage. |
| 75 | // See ComposeMessage for replyToMsgID / references semantics. |
| 76 | func ComposeMultipartMessage(from string, to []string, cc []string, subject, textBody, htmlBody, replyToMsgID string, references []string, fromDomain, replyTo, conversationID string) ([]byte, error) { |
| 77 | if htmlBody == "" { |
| 78 | return ComposeMessage(from, to, cc, subject, textBody, "text/plain", replyToMsgID, references, fromDomain, replyTo, conversationID) |
| 79 | } |
| 80 | |
| 81 | boundary := generateBoundary() |
| 82 | |
| 83 | var buf strings.Builder |
| 84 | writeHeader := headerWriter(&buf) |
| 85 | |
| 86 | writeHeader("From", from) |
| 87 | if len(to) > 0 { |
| 88 | writeHeader("To", strings.Join(to, ", ")) |
| 89 | } |
| 90 | if len(cc) > 0 { |
| 91 | writeHeader("Cc", strings.Join(cc, ", ")) |
| 92 | } |
| 93 | if replyTo != "" { |
| 94 | writeHeader("Reply-To", replyTo) |
| 95 | } |
| 96 | writeHeader("Subject", mime.QEncoding.Encode("utf-8", subject)) |
| 97 | writeHeader("Date", time.Now().UTC().Format(time.RFC1123Z)) |
| 98 | writeHeader("MIME-Version", "1.0") |
| 99 | writeHeader("Content-Type", fmt.Sprintf("multipart/alternative; boundary=%q", boundary)) |
| 100 | |
| 101 | writeThreadingHeaders(writeHeader, replyToMsgID, references) |
| 102 | if conversationID != "" { |
| 103 | writeHeader("X-E2A-Conversation-ID", conversationID) |
| 104 | } |
| 105 | |
| 106 | buf.WriteString("\r\n") |
| 107 | |
| 108 | // text/plain part |
| 109 | buf.WriteString("--" + boundary + "\r\n") |
| 110 | buf.WriteString("Content-Type: text/plain; charset=utf-8\r\n\r\n") |
| 111 | buf.WriteString(textBody) |
| 112 | buf.WriteString("\r\n") |
| 113 | |
| 114 | // text/html part |
| 115 | buf.WriteString("--" + boundary + "\r\n") |
| 116 | buf.WriteString("Content-Type: text/html; charset=utf-8\r\n\r\n") |
| 117 | buf.WriteString(htmlBody) |
| 118 | buf.WriteString("\r\n") |
| 119 | |
| 120 | // closing boundary |
| 121 | buf.WriteString("--" + boundary + "--\r\n") |
| 122 | |
| 123 | return []byte(buf.String()), nil |
| 124 | } |
| 125 | |
| 126 | // ComposeMessageWithAttachments builds an RFC 2822 multipart/mixed email with attachments. |
| 127 | // If no attachments are provided, falls back to ComposeMultipartMessage. |