Skip to content

Instantly share code, notes, and snippets.

@dcormier
Last active October 25, 2023 02:36
Show Gist options
  • Save dcormier/46d110cb7e14d5749828958a9c2d9278 to your computer and use it in GitHub Desktop.
Save dcormier/46d110cb7e14d5749828958a9c2d9278 to your computer and use it in GitHub Desktop.
golang: parsing emails with mime, mime/multipart and net/mail packages
pacakge msgtest
import (
"io"
"mime"
"mime/multipart"
"net/mail"
"net/textproto"
"os"
"path/filepath"
"strings"
"testing"
"github.com/pkg/errors"
)
func TestMsgParse(t *testing.T) {
r, _ := os.Open(filepath.Join("testdata", "yourfile.eml"))
readMsg(t, r)
}
func getMediaType(t *testing.T, h textproto.MIMEHeader) (mediaType string, params map[string]string) {
cth := h.Get(hnContentType)
mediaType, params, err := mime.ParseMediaType(cth)
if err != nil {
t.Fatalf("Failed to parse content type header %q: %v", cth, err)
}
return mediaType, params
}
func isMultipart(mediaType string) bool {
return strings.HasPrefix(mediaType, "multipart/")
}
func readMultipart(t *testing.T, r *multipart.Reader) {
for {
p, err := r.NextPart()
switch err {
case nil:
// Carry on
case io.EOF:
return
default:
t.Fatalf("%+v", errors.WithStack(err))
}
readPart(t, p)
}
}
func readPart(t *testing.T, p *multipart.Part) {
mediaType, params := getMediaType(t, p.Header)
if isMultipart(mediaType) {
boundary := params[hpBoundary]
t.Logf("Reading multipart with boundary %q", boundary)
pr := multipart.NewReader(p, boundary)
readMultipart(t, pr)
return
} else if mediaType == "message/rfc822" {
t.Log("Part is attached email")
readMsg(t, p)
}
t.Logf("Not multipart: %s", p.Header.Get(hnContentType))
}
func readMsg(t *testing.T, r io.Reader) {
t.Log("Reading message")
m, err := mail.ReadMessage(r)
if err != nil {
t.Fatalf("%+v", errors.WithStack(err))
}
mediaType, params := getMediaType(t, textproto.MIMEHeader(m.Header))
if !isMultipart(mediaType) {
t.Logf("Not multipart: %s", m.Header.Get(hnContentType))
return
}
t.Logf("Reading multipart with boundary %q", params[hpBoundary])
mr := multipart.NewReader(m.Body, params[hpBoundary])
readMultipart(t, mr)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment