golang流式处理互联网消息格式和邮件消息插件库go-message的使用

golang流式处理互联网消息格式和邮件消息插件库go-message的使用

go-message 是一个用于处理互联网消息格式的 Go 库。它实现了以下 RFC 标准:

  • RFC 5322: 互联网消息格式
  • RFC 2045, RFC 2046 和 RFC 2047: 多用途互联网邮件扩展(MIME)
  • RFC 2183: Content-Disposition 头字段

特性

  • 流式 API
  • 自动编码和字符集处理(要解码所有字符集,需要在应用中添加 import _ "github.com/emersion/go-message/charset"
  • 包含 mail 子包用于读写邮件消息
  • 支持 DKIM
  • 包含 textproto 子包实现有线格式

示例代码

1. 创建简单的邮件消息

package main

import (
	"bytes"
	"fmt"
	"github.com/emersion/go-message"
	"github.com/emersion/go-message/mail"
	"io"
	"time"
)

func main() {
	// 创建一个缓冲区来存储消息
	var b bytes.Buffer

	// 创建邮件消息头
	h := mail.NewHeader()
	h.SetDate(time.Now())
	h.SetAddressList("From", []*mail.Address{{Name: "发件人", Address: "from@example.com"}})
	h.SetAddressList("To", []*mail.Address{{Name: "收件人", Address: "to@example.com"}})
	h.SetSubject("测试邮件")

	// 创建邮件消息
	w, err := mail.CreateWriter(&b, h)
	if err != nil {
		panic(err)
	}

	// 添加文本部分
	tw, err := w.CreateInline()
	if err != nil {
		panic(err)
	}
	th := mail.NewTextHeader()
	th.Set("Content-Type", "text/plain; charset=UTF-8")
	if _, err := tw.WriteHeader(th); err != nil {
		panic(err)
	}
	if _, err := io.WriteString(tw, "这是一封测试邮件。"); err != nil {
		panic(err)
	}

	// 关闭写入器
	if err := w.Close(); err != nil {
		panic(err)
	}

	// 输出生成的邮件
	fmt.Println(b.String())
}

2. 解析邮件消息

package main

import (
	"fmt"
	"github.com/emersion/go-message"
	"github.com/emersion/go-message/mail"
	"io"
	"strings"
)

func main() {
	// 示例邮件内容
	rawMessage := `From: from@example.com
To: to@example.com
Subject: 测试邮件
Date: Wed, 11 May 2022 10:00:00 +0800
Content-Type: multipart/alternative; boundary="boundary"

--boundary
Content-Type: text/plain; charset=UTF-8

这是一封测试邮件。
--boundary--`

	// 创建邮件阅读器
	r := strings.NewReader(rawMessage)
	e, err := message.Read(r)
	if err != nil {
		panic(err)
	}

	// 解析为邮件消息
	mr, err := mail.CreateReader(e)
	if err != nil {
		panic(err)
	}

	// 打印邮件头信息
	fmt.Println("From:", mr.Header.Get("From"))
	fmt.Println("To:", mr.Header.Get("To"))
	fmt.Println("Subject:", mr.Header.Get("Subject"))
	fmt.Println("Date:", mr.Header.Get("Date"))

	// 处理邮件正文
	for {
		p, err := mr.NextPart()
		if err == io.EOF {
			break
		} else if err != nil {
			panic(err)
		}

		switch h := p.Header.(type) {
		case *mail.InlineHeader:
			// 内联文本部分
			body, _ := io.ReadAll(p.Body)
			fmt.Printf("Text content: %s\n", body)
		case *mail.AttachmentHeader:
			// 附件部分
			filename, _ := h.Filename()
			fmt.Printf("Attachment: %s\n", filename)
		}
	}
}

3. 处理 MIME 消息

package main

import (
	"bytes"
	"fmt"
	"github.com/emersion/go-message"
	"io"
)

func main() {
	// 示例 MIME 消息
	rawMessage := `Content-Type: multipart/mixed; boundary="boundary"

--boundary
Content-Type: text/plain; charset=UTF-8

这是文本部分。
--boundary
Content-Type: application/json

{"key": "value"}
--boundary--`

	// 创建消息阅读器
	r := strings.NewReader(rawMessage)
	e, err := message.Read(r)
	if err != nil {
		panic(err)
	}

	// 检查是否是 multipart 消息
	if mr := e.MultipartReader(); mr != nil {
		// 遍历所有部分
		for {
			p, err := mr.NextPart()
			if err == io.EOF {
				break
			} else if err != nil {
				panic(err)
			}

			// 获取内容类型
			contentType, _, _ := p.Header.ContentType()
			body, _ := io.ReadAll(p.Body)
			
			fmt.Printf("Content-Type: %s\n", contentType)
			fmt.Printf("Content: %s\n", body)
		}
	}
}

许可证

MIT


更多关于golang流式处理互联网消息格式和邮件消息插件库go-message的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang流式处理互联网消息格式和邮件消息插件库go-message的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


go-message库使用指南:流式处理互联网消息与邮件

go-message是一个用于处理互联网消息格式(如MIME)和邮件消息的Go语言库。它提供了流式处理能力,非常适合处理大消息而不消耗过多内存。

基本概念

go-message支持以下功能:

  • 解析和生成MIME消息
  • 处理邮件消息(RFC 5322)
  • 流式读写
  • 支持附件和内联内容
  • 处理多部分消息

安装

go get github.com/emersion/go-message

基本使用示例

1. 创建简单文本邮件

package main

import (
	"bytes"
	"fmt"
	"github.com/emersion/go-message"
	"github.com/emersion/go-message/mail"
	"io"
	"time"
)

func createSimpleEmail() (string, error) {
	var b bytes.Buffer
	
	// 创建邮件头
	h := mail.NewHeader()
	h.SetAddressList("From", []*mail.Address{{Name: "张三", Address: "zhangsan@example.com"}})
	h.SetAddressList("To", []*mail.Address{{Name: "李四", Address: "lisi@example.com"}})
	h.Set("Subject", "测试邮件")
	h.SetDate("Date", time.Now())

	// 创建邮件实体
	w, err := mail.CreateTextWriter(&b, h)
	if err != nil {
		return "", err
	}
	
	// 写入邮件正文
	_, err = io.WriteString(w, "这是一封测试邮件。\r\n")
	if err != nil {
		return "", err
	}
	
	err = w.Close()
	if err != nil {
		return "", err
	}
	
	return b.String(), nil
}

func main() {
	email, err := createSimpleEmail()
	if err != nil {
		panic(err)
	}
	fmt.Println(email)
}

2. 解析邮件

func parseEmail(email string) error {
	// 创建消息读取器
	r := strings.NewReader(email)
	mr, err := message.Read(r)
	if err != nil {
		return err
	}

	// 解析为邮件消息
	mailReader, err := mail.CreateReader(mr)
	if err != nil {
		return err
	}

	// 打印头信息
	fmt.Println("From:", mailReader.Header.Get("From"))
	fmt.Println("To:", mailReader.Header.Get("To"))
	fmt.Println("Subject:", mailReader.Header.Get("Subject"))

	// 处理邮件正文
	for {
		p, err := mailReader.NextPart()
		if err == io.EOF {
			break
		} else if err != nil {
			return err
		}

		switch h := p.Header.(type) {
		case *mail.InlineHeader:
			fmt.Println("Inline text part:")
			body, _ := io.ReadAll(p.Body)
			fmt.Println(string(body))
		case *mail.AttachmentHeader:
			filename, _ := h.Filename()
			fmt.Println("Attachment:", filename)
		}
	}

	return nil
}

3. 创建带附件的邮件

func createEmailWithAttachment() (string, error) {
	var b bytes.Buffer
	
	// 创建多部分消息
	h := mail.NewHeader()
	h.SetAddressList("From", []*mail.Address{{Name: "张三", Address: "zhangsan@example.com"}})
	h.SetAddressList("To", []*mail.Address{{Name: "李四", Address: "lisi@example.com"}})
	h.Set("Subject", "带附件的测试邮件")
	
	// 创建多部分写入器
	mw, err := mail.CreateWriter(&b, h)
	if err != nil {
		return "", err
	}

	// 添加文本部分
	tw, err := mw.CreateInline()
	if err != nil {
		return "", err
	}
	th := mail.NewTextHeader()
	th.Set("Content-Type", "text/plain; charset=UTF-8")
	_, err = io.WriteString(tw, "这是一封带附件的测试邮件。\r\n")
	tw.Close()

	// 添加附件
	aw, err := mw.CreateAttachment("report.pdf", "application/pdf")
	if err != nil {
		return "", err
	}
	_, err = io.WriteString(aw, "PDF文件内容...")
	aw.Close()

	mw.Close()
	return b.String(), nil
}

高级特性

1. 流式处理大附件

func streamLargeAttachment(dest io.Writer, attachmentPath string) error {
	// 创建邮件头
	h := mail.NewHeader()
	// 设置头信息...

	mw, err := mail.CreateWriter(dest, h)
	if err != nil {
		return err
	}

	// 添加文本部分
	tw, err := mw.CreateInline()
	// 写入文本内容...
	tw.Close()

	// 添加大附件
	aw, err := mw.CreateAttachment("largefile.bin", "application/octet-stream")
	if err != nil {
		return err
	}
	
	// 这里可以替换为实际的文件读取
	file, err := os.Open(attachmentPath)
	if err != nil {
		return err
	}
	defer file.Close()
	
	_, err = io.Copy(aw, file)
	if err != nil {
		return err
	}
	
	aw.Close()
	mw.Close()
	return nil
}

2. 处理HTML邮件

func createHTMLEmail() (string, error) {
	var b bytes.Buffer
	
	h := mail.NewHeader()
	// 设置头信息...

	// 创建多部分替代消息(同时包含HTML和纯文本)
	mw, err := mail.CreateWriter(&b, h)
	if err != nil {
		return "", err
	}

	// 纯文本版本
	tw, err := mw.CreateInline()
	th := mail.NewTextHeader()
	th.Set("Content-Type", "text/plain; charset=UTF-8")
	io.WriteString(tw, "这是纯文本版本...")
	tw.Close()

	// HTML版本
	hw, err := mw.CreateInline()
	hh := mail.NewTextHeader()
	hh.Set("Content-Type", "text/html; charset=UTF-8")
	io.WriteString(hw, "<html><body><h1>这是HTML版本</h1></body></html>")
	hw.Close()

	mw.Close()
	return b.String(), nil
}

注意事项

  1. 流式处理:go-message设计用于流式处理,适合处理大消息而不会耗尽内存
  2. 内存效率:尽可能使用io.Copy而不是读取整个内容到内存
  3. 错误处理:始终检查Close()方法的返回值
  4. 并发安全:消息读取器和写入器通常不是并发安全的

go-message是一个功能强大且高效的库,特别适合需要处理大量邮件或大附件的应用场景。通过流式处理,它可以保持低内存占用,同时提供灵活的API来处理各种消息格式。

回到顶部