NOTE: Message-ID is intentionally omitted from composed messages. SES assigns its own Message-ID on send, and we capture it from the SMTP response. This avoids a mismatch where recipients see the SES ID but we tracked a different one. ComposeMessage builds an RFC 2822 email message (single content t
(from string, to []string, cc []string, subject, body, contentType, replyToMsgID string, references []string, fromDomain, replyTo, conversationID string)
| 37 | // (Gmail) can't anchor the reply to the existing thread and forks a new one. |
| 38 | // With the full chain, the client matches on ANY prior ID and threads correctly. |
| 39 | func ComposeMessage(from string, to []string, cc []string, subject, body, contentType, replyToMsgID string, references []string, fromDomain, replyTo, conversationID string) ([]byte, error) { |
| 40 | if contentType == "" { |
| 41 | contentType = "text/plain" |
| 42 | } |
| 43 | |
| 44 | var buf strings.Builder |
| 45 | writeHeader := headerWriter(&buf) |
| 46 | |
| 47 | writeHeader("From", from) |
| 48 | if len(to) > 0 { |
| 49 | writeHeader("To", strings.Join(to, ", ")) |
| 50 | } |
| 51 | if len(cc) > 0 { |
| 52 | writeHeader("Cc", strings.Join(cc, ", ")) |
| 53 | } |
| 54 | if replyTo != "" { |
| 55 | writeHeader("Reply-To", replyTo) |
| 56 | } |
| 57 | writeHeader("Subject", mime.QEncoding.Encode("utf-8", subject)) |
| 58 | writeHeader("Date", time.Now().UTC().Format(time.RFC1123Z)) |
| 59 | writeHeader("MIME-Version", "1.0") |
| 60 | writeHeader("Content-Type", contentType+"; charset=utf-8") |
| 61 | |
| 62 | writeThreadingHeaders(writeHeader, replyToMsgID, references) |
| 63 | if conversationID != "" { |
| 64 | writeHeader("X-E2A-Conversation-ID", conversationID) |
| 65 | } |
| 66 | |
| 67 | buf.WriteString("\r\n") |
| 68 | buf.WriteString(body) |
| 69 | |
| 70 | return []byte(buf.String()), nil |
| 71 | } |
| 72 | |
| 73 | // ComposeMultipartMessage builds an RFC 2822 multipart/alternative email with text and HTML parts. |
| 74 | // If htmlBody is empty, falls back to a single text/plain message via ComposeMessage. |