package email import ( "bytes" "net/mail" "strings" "github.com/jhillyerd/enmime" ) type ParsedEmail struct { MessageID string FromAddress string FromName string ToAddresses []string CcAddresses []string BccAddresses []string ReplyToAddress string ReturnPath string Subject string Snippet string Size int64 Attachments []ParsedAttachment } type ParsedAttachment struct { Filename string ContentType string ContentID string Size int64 IsInline bool } func Parse(rawMessage []byte) (*ParsedEmail, error) { envelope, parseError := enmime.ReadEnvelope(bytes.NewReader(rawMessage)) if parseError != nil { return nil, parseError } return &ParsedEmail{ MessageID: envelope.GetHeader("Message-ID"), FromAddress: extractAddress(envelope.GetHeader("From")), FromName: extractName(envelope.GetHeader("From")), ToAddresses: extractAddressList(envelope.GetHeader("To")), CcAddresses: extractAddressList(envelope.GetHeader("Cc")), BccAddresses: extractAddressList(envelope.GetHeader("Bcc")), ReplyToAddress: envelope.GetHeader("Reply-To"), ReturnPath: envelope.GetHeader("Return-Path"), Subject: envelope.GetHeader("Subject"), Snippet: generateSnippet(envelope.Text), Size: int64(len(rawMessage)), Attachments: extractAttachments(envelope), }, nil } func extractAddress(rawHeader string) string { parsed, parseError := mail.ParseAddress(rawHeader) if parseError != nil { return rawHeader } return parsed.Address } func extractName(rawHeader string) string { parsed, parseError := mail.ParseAddress(rawHeader) if parseError != nil { return "" } return parsed.Name } func extractAddressList(rawHeader string) []string { if rawHeader == "" { return nil } addresses, parseError := mail.ParseAddressList(rawHeader) if parseError != nil { return []string{rawHeader} } extracted := make([]string, len(addresses)) for index, address := range addresses { extracted[index] = address.Address } return extracted } func generateSnippet(textBody string) string { trimmed := strings.TrimSpace(textBody) if len(trimmed) <= SnippetLength { return trimmed } return trimmed[:SnippetLength] } func extractAttachments(envelope *enmime.Envelope) []ParsedAttachment { var attachments []ParsedAttachment for _, attachment := range envelope.Attachments { attachments = append(attachments, ParsedAttachment{ Filename: attachment.FileName, ContentType: attachment.ContentType, ContentID: attachment.ContentID, Size: int64(len(attachment.Content)), IsInline: false, }) } for _, inline := range envelope.Inlines { attachments = append(attachments, ParsedAttachment{ Filename: inline.FileName, ContentType: inline.ContentType, ContentID: inline.ContentID, Size: int64(len(inline.Content)), IsInline: true, }) } return attachments }