gpt4 book ai didi

email - 如何在 Go 中为电子邮件创建嵌套的多部分/MIME 信封?

转载 作者:IT老高 更新时间:2023-10-28 13:10:55 29 4
gpt4 key购买 nike

我正在研究如何构建 multipart/mime envelopes用于 Go 中的电子邮件。以下代码生成正确嵌套的主体 - 但边界未正确插入。

您可以在 https://play.golang.org/p/XLc4DQFObRn 上查看演示

package main

import (
"bytes"
"fmt"
"io"
"log"
"math/rand"
"mime/multipart"
"mime/quotedprintable"
"net/textproto"
)

// multipart/mixed
// |- multipart/related
// | |- multipart/alternative
// | | |- text/plain
// | | `- text/html
// | `- inlines..
// `- attachments..


func main() {

body := &bytes.Buffer{}
writer := multipart.NewWriter(body)

var part io.Writer
var err error

// Text Content
part, err = writer.CreatePart(textproto.MIMEHeader{"Content-Type": {"multipart/alternative"}})
if err != nil {
log.Fatal(err)
}

childWriter := multipart.NewWriter(part)

var subpart io.Writer
for _, contentType := range []string{"text/plain", "text/html"} {
subpart, err = CreateQuoteTypePart(childWriter, contentType)
if err != nil {
log.Fatal(err)
}
_, err := subpart.Write([]byte("This is a line of text that needs to be wrapped by quoted-printable before it goes to far.\r\n\r\n"))
if err != nil {
log.Fatal(err)
}
}

// Attachments
filename := fmt.Sprintf("File_%d.jpg", rand.Int31())
part, err = writer.CreatePart(textproto.MIMEHeader{"Content-Type": {"application/octet-stream"}, "Content-Disposition": {"attachment; filename=" + filename}})
if err != nil {
log.Fatal(err)
}
part.Write([]byte("AABBCCDDEEFF"))

writer.Close()

fmt.Print(`From: Bob <bob@example.com>
To: Alice <alias@example.com>
Subject: Formatted text mail
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary=`)
fmt.Println(writer.Boundary())
fmt.Println(body.String())

}

// https://github.com/domodwyer/mailyak/blob/master/attachments.go#L142
func CreateQuoteTypePart(writer *multipart.Writer, contentType string) (part io.Writer, err error) {
header := textproto.MIMEHeader{
"Content-Type": []string{contentType},
"Content-Transfer-Encoding": []string{"quoted-printable"},
}

part, err = writer.CreatePart(header)
if err != nil {
return
}
part = quotedprintable.NewWriter(part)
return
}

我想坚持使用标准库 (stdlib) 中的答案并避免 third派对 attempts飞翔吧。

最佳答案

不幸的是,用于编写多部分 MIME 消息的标准库支持有一个糟糕的嵌套 API。问题是你必须在创建 writer 之前在 header 中设置 boundary 字符串,但是在创建 writer 之前生成的边界字符串显然是不可用的。所以你必须明确设置边界字符串。

这是我的解决方案 (runnable in the Go Playground),为简洁起见进行了简化。我选择使用外部写入器的边界来设置内部写入器的边界,并添加标签以便在读取输出时更容易跟踪。

package main

import ("bytes"; "fmt"; "io"; "log"; "math/rand"; "mime/multipart"; "net/textproto")

// multipart/mixed
// |- multipart/related
// | |- multipart/alternative
// | | |- text/plain
// | | `- text/html
// | `- inlines..
// `- attachments..

func main() {
mixedContent := &bytes.Buffer{}
mixedWriter := multipart.NewWriter(mixedContent)

// related content, inside mixed
var newBoundary = "RELATED-" + mixedWriter.Boundary()
mixedWriter.SetBoundary(first70("MIXED-" + mixedWriter.Boundary()))

relatedWriter, newBoundary := nestedMultipart(mixedWriter, "multipart/related", newBoundary)
altWriter, newBoundary := nestedMultipart(relatedWriter, "multipart/alternative", "ALTERNATIVE-" + newBoundary)

// Actual content alternatives (finally!)
var childContent io.Writer

childContent, _ = altWriter.CreatePart(textproto.MIMEHeader{"Content-Type": {"text/plain"}})
childContent.Write([]byte("This is a line of text\r\n\r\n"))
childContent, _ = altWriter.CreatePart(textproto.MIMEHeader{"Content-Type": {"text/html"}})
childContent.Write([]byte("<html>HTML goes here\r\n</html>\r\n"))
altWriter.Close()

relatedWriter.Close()

// Attachments
filename := fmt.Sprintf("File_%d.jpg", rand.Int31())
var fileContent io.Writer

fileContent, _ = mixedWriter.CreatePart(textproto.MIMEHeader{"Content-Type": {"application/octet-stream"}, "Content-Disposition": {"attachment; filename=" + filename}})
fileContent.Write([]byte("AABBCCDDEEFF"))

mixedWriter.Close()

fmt.Print(`From: Bob <bob@example.com>
To: Alice <alias@example.com>
Subject: Formatted text mail
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary=`)
fmt.Print(mixedWriter.Boundary(), "\n\n")
fmt.Println(mixedContent.String())

}

func nestedMultipart(enclosingWriter *multipart.Writer, contentType, boundary string) (nestedWriter *multipart.Writer, newBoundary string) {

var contentBuffer io.Writer
var err error

boundary = first70(boundary)
contentWithBoundary := contentType + "; boundary=\"" + boundary + "\""
contentBuffer, err = enclosingWriter.CreatePart(textproto.MIMEHeader{"Content-Type": {contentWithBoundary}})
if err != nil {
log.Fatal(err)
}

nestedWriter = multipart.NewWriter(contentBuffer)
newBoundary = nestedWriter.Boundary()
nestedWriter.SetBoundary(boundary)
return
}

func first70(str string) string {
if len(str) > 70 {
return string(str[0:69])
}
return str
}

关于email - 如何在 Go 中为电子邮件创建嵌套的多部分/MIME 信封?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53752824/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com