使用golang的smtp和multipart时获取附件中的ATT001.txt文件(0字节)作为额外附件

问题描述 投票:0回答:1

请检查

ToBytes()
方法,在我看来问题出在哪里。

package mail

import (
    "bytes"
    "encoding/base64"
    "fmt"
    "mime/multipart"
    "net/http"
    "net/smtp"
    "os"
    "path/filepath"
    "strings"

    "github.com/personal-mailer/props"
)

type Sender struct {
    auth smtp.Auth
}

type Message struct {
    To          []string
    CC          []string
    BCC         []string
    Subject     string
    Body        string
    Attachments map[string][]byte
}

func New(smtpCred props.SMTPCredentials) *Sender {
    auth := smtp.PlainAuth("", smtpCred.User, smtpCred.Pass, smtpCred.Host)
    return &Sender{auth}
}

func (s *Sender) Send(m *Message, smtpCred props.SMTPCredentials) error {
    hostAndport := fmt.Sprintf("%s:%d", smtpCred.Host, smtpCred.Port)
    auth := smtp.PlainAuth("", smtpCred.User, smtpCred.Pass, smtpCred.Host)
    return smtp.SendMail(hostAndport, auth, "[email protected]", m.To, m.ToBytes())
}

func NewMessage(s, b string) *Message {
    return &Message{Subject: s, Body: b, Attachments: make(map[string][]byte)}
}

func (m *Message) AttachFile(filePaths []string) error {
    for _, path := range filePaths {
        b, err := os.ReadFile(path)
        if err != nil {
            return err
        }

        _, fileName := filepath.Split(path)
        m.Attachments[fileName] = b
    }

    return nil
}

func (m *Message) ToBytes() []byte {
    buf := bytes.NewBuffer(nil)
    withAttachments := len(m.Attachments) > 0
    buf.WriteString(fmt.Sprintf("From: %s\n", "[email protected]"))
    buf.WriteString(fmt.Sprintf("Subject: %s\n", m.Subject))
    buf.WriteString(fmt.Sprintf("To: %s\n", strings.Join(m.To, ",")))
    if len(m.CC) > 0 {
        buf.WriteString(fmt.Sprintf("Cc: %s\n", strings.Join(m.CC, ",")))
    }

    if len(m.BCC) > 0 {
        buf.WriteString(fmt.Sprintf("Bcc: %s\n", strings.Join(m.BCC, ",")))
    }

    buf.WriteString("MIME-Version: 1.0\n")
    writer := multipart.NewWriter(buf)
    boundary := writer.Boundary()
    if withAttachments {
        buf.WriteString(fmt.Sprintf("Content-Type: multipart/mixed; boundary=%s\n\n", boundary))
        // Add the email body as a part
        buf.WriteString(fmt.Sprintf("--%s\n", boundary))
        buf.WriteString("Content-Type: text/plain; charset=utf-8\n")
        buf.WriteString(m.Body)
        buf.WriteString(fmt.Sprintf("\n--%s\n", boundary))
        // Add attachments
        for k, v := range m.Attachments {
            buf.WriteString(fmt.Sprintf("--%s\n", boundary))
            buf.WriteString(fmt.Sprintf("Content-Type: %s\n", http.DetectContentType(v)))
            buf.WriteString("Content-Transfer-Encoding: base64\n")
            buf.WriteString(fmt.Sprintf("Content-Disposition: attachment; filename=\"%s\"\n\n", k))

            b := make([]byte, base64.StdEncoding.EncodedLen(len(v)))
            base64.StdEncoding.Encode(b, v)
            buf.Write(b)
            buf.WriteString(fmt.Sprintf("\n--%s\n", boundary))
            buf.WriteString("--\n")
            buf.WriteString("--\n")

        }
    } else {
        buf.WriteString("Content-Type: text/plain; charset=utf-8\n\n")
        buf.WriteString(m.Body)
    }

    return buf.Bytes()
}

代码正在工作,就像收件人正在接收带有附件(如果包含)的邮件一样。

我正在尝试使用边界来了解为什么要附加此 att00001.txt 文件,但这不起作用

go smtp multipart
1个回答
0
投票

如果您能实际按照您的意图记录您的代码,以便人们能够理解您的实现是否被破坏或者您对 MIME 的理解是否错误,这将会很有帮助。

很明显,每个附件后面的两个

buf.WriteString("--\n")
都是错误的(不清楚你认为它们应该做什么)并且结束边界(在最后一个 MIME 部分之后)丢失。

有关多部分内容类型的更多信息,请参阅 RFC 2046 第 5.1 节,特别是关于边界作用的 5.1.1 节。 另外,由于您已经使用了 multipart/mime,因此使用 multipart.CreatePart 来处理复杂的 MIME 部分和边界内容而不是自己实现会更有意义。

© www.soinside.com 2019 - 2024. All rights reserved.