extractThreadInfo parses threading headers from a raw RFC 2822 message.
(body []byte)
| 734 | |
| 735 | // extractThreadInfo parses threading headers from a raw RFC 2822 message. |
| 736 | func extractThreadInfo(body []byte) threadInfo { |
| 737 | msg, err := mail.ReadMessage(bytes.NewReader(body)) |
| 738 | if err != nil { |
| 739 | return threadInfo{} |
| 740 | } |
| 741 | var refs []string |
| 742 | if r := msg.Header.Get("References"); r != "" { |
| 743 | for _, ref := range strings.Fields(r) { |
| 744 | refs = append(refs, ref) |
| 745 | } |
| 746 | } |
| 747 | // Extract From header email address |
| 748 | fromHeader := "" |
| 749 | if addr, err := mail.ParseAddress(msg.Header.Get("From")); err == nil { |
| 750 | fromHeader = addr.Address |
| 751 | } |
| 752 | return threadInfo{ |
| 753 | MessageID: msg.Header.Get("Message-Id"), |
| 754 | Subject: decodeMIMEHeader(msg.Header.Get("Subject")), |
| 755 | InReplyTo: msg.Header.Get("In-Reply-To"), |
| 756 | References: refs, |
| 757 | From: fromHeader, |
| 758 | // RFC 5322 § 3.6.2 allows multiple addresses in Reply-To. Mirror |
| 759 | // the same parser used for To/Cc so display names get stripped |
| 760 | // the same way and the field shape is uniform across consumers. |
| 761 | ReplyTo: extractAddressList(msg.Header.Get("Reply-To")), |
| 762 | To: extractAddressList(msg.Header.Get("To")), |
| 763 | CC: extractAddressList(msg.Header.Get("Cc")), |
| 764 | ConversationID: msg.Header.Get("X-E2A-Conversation-Id"), |
| 765 | } |
| 766 | } |
| 767 | |
| 768 | // decodeMIMEHeader decodes any RFC 2047 encoded-word runs in a header value |
| 769 | // (e.g. `=?utf-8?Q?caf=C3=A9?=` → `café`). Used for display fields like |