You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Go语言net/mail库解析多格式邮件的求助

解决Go net/mail解析Apple Mail多部分邮件并通过SendGrid正常转发的问题

核心问题分析

Apple Mail发送的HTML邮件通常是multipart/alternative或multipart/mixed类型,net/mail库仅会将邮件解析为*mail.Message结构,其中的Body是带分隔符的原始多部分内容。直接转发该内容会导致SendGrid无法正确识别各部分的边界与类型,进而引发显示异常、附件失效等问题。

正确解析与处理步骤

1. 拆分多部分邮件结构

不要直接使用msg.Body,需先解析Content-Type提取边界,再拆分出各个独立部分:

import (
    "io"
    "mime"
    "mime/multipart"
    "net/mail"
    "strings"
)

func parseMultipartMessage(msg *mail.Message) ([]*multipart.Part, error) {
    contentType := msg.Header.Get("Content-Type")
    mediaType, params, err := mime.ParseMediaType(contentType)
    if err != nil {
        return nil, err
    }

    // 非多部分邮件直接封装为单部分返回
    if !strings.HasPrefix(mediaType, "multipart/") {
        part := &multipart.Part{Header: msg.Header}
        part.SetBody(msg.Body)
        return []*multipart.Part{part}, nil
    }

    boundary := params["boundary"]
    reader := multipart.NewReader(msg.Body, boundary)
    var parts []*multipart.Part
    for {
        part, err := reader.NextPart()
        if err == io.EOF {
            break
        }
        if err != nil {
            return nil, err
        }
        parts = append(parts, part)
    }
    return parts, nil
}

2. 重组内容适配SendGrid转发

遍历拆分后的部分,分类处理正文与附件,再用SendGrid SDK构建标准邮件结构:

import (
    "github.com/sendgrid/sendgrid-go"
    "github.com/sendgrid/sendgrid-go/helpers/mail"
    "io/ioutil"
    "mime"
)

func forwardWithSendGrid(originalMsg *mail.Message, parts []*multipart.Part) error {
    from := mail.NewEmail(originalMsg.Header.Get("From"), originalMsg.Header.Get("From"))
    to := mail.NewEmail(originalMsg.Header.Get("To"), originalMsg.Header.Get("To"))
    subject := originalMsg.Header.Get("Subject")

    var plainContent, htmlContent string
    var attachments []*mail.Attachment

    for _, part := range parts {
        contentType := part.Header.Get("Content-Type")
        mediaType, _, err := mime.ParseMediaType(contentType)
        if err != nil {
            continue
        }

        body, err := ioutil.ReadAll(part)
        if err != nil {
            continue
        }

        switch mediaType {
        case "text/plain":
            plainContent = string(body)
        case "text/html":
            htmlContent = string(body)
        default:
            // 处理附件,提取文件名与 disposition
            disp := part.Header.Get("Content-Disposition")
            _, params, err := mime.ParseMediaType(disp)
            if err != nil {
                continue
            }
            filename := params["filename"]
            attachment := mail.NewAttachment()
            attachment.SetContent(string(body))
            attachment.SetFilename(filename)
            attachment.SetType(contentType)
            attachment.SetDisposition(disp)
            attachments = append(attachments, attachment)
        }
    }

    message := mail.NewSingleEmail(from, subject, to, plainContent, htmlContent)
    message.Attachments = attachments

    client := sendgrid.NewSendClient("YOUR_SENDGRID_API_KEY")
    _, err := client.Send(message)
    return err
}

3. 处理嵌套多部分与编码

若遇到嵌套的多部分结构(比如multipart/mixed包含multipart/alternative),需递归解析所有子部分;net/mail的Part会自动处理quoted-printable或base64编码,直接读取内容即可,无需手动解码。

关键注意事项

  • 禁止直接转发原始msg.Body,必须拆分后重组;
  • 保留原始邮件的字符编码(从Content-Type的charset参数获取),避免正文乱码;
  • SendGrid会自动生成新的多部分边界,无需手动添加原始分隔符;
  • 测试时需覆盖Apple Mail发送的HTML+纯文本+附件场景,验证转发后的显示与附件完整性。

内容的提问来源于stack exchange,提问作者Jomy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 03:35:29