Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to decode mail body in Go

I'm working on an email client and part of this I need to decode the email body. I'm using the IMAP package to fetch the messages but there is no "decode" method. I also checked the net/mail package with no luck either. Only the headers seem to have a parser. Is there any lib that I can use?

like image 962
hey Avatar asked Jul 22 '14 09:07

hey


3 Answers

Once you parsed the email with net/mail and have a Message, if the body is quoted-printable encoded (Content-Transfer-Encoding: quoted-printable):

  • if using Go 1.5, use the quotedprintable package from the standard library
  • if using an older version of Go, use my drop-in replacement

Example:

r := quotedprintable.NewReader(msg.Body)
body, err := ioutil.ReadAll(r) // body now contains the decoded body

If the body is encoded using base64 (Content-Transfer-Encoding: base64), you should use the encoding/base64 package.

like image 86
Ale Avatar answered Sep 19 '22 21:09

Ale


I've had some luck using github.com/jhillyerd/enmime to break out both headers and body parts. Given an io.Reader r:

// Parse message body
env, _ := enmime.ReadEnvelope(r)
// Headers can be retrieved via Envelope.GetHeader(name).
fmt.Printf("From: %v\n", env.GetHeader("From"))
// Address-type headers can be parsed into a list of decoded mail.Address structs.
alist, _ := env.AddressList("To")
for _, addr := range alist {
  fmt.Printf("To: %s <%s>\n", addr.Name, addr.Address)
}
fmt.Printf("Subject: %v\n", env.GetHeader("Subject"))

// The plain text body is available as mime.Text.
fmt.Printf("Text Body: %v chars\n", len(env.Text))

// The HTML body is stored in mime.HTML.
fmt.Printf("HTML Body: %v chars\n", len(env.HTML))

// mime.Inlines is a slice of inlined attacments.
fmt.Printf("Inlines: %v\n", len(env.Inlines))

// mime.Attachments contains the non-inline attachments.
fmt.Printf("Attachments: %v\n", len(env.Attachments))
like image 28
Allen Luce Avatar answered Sep 17 '22 21:09

Allen Luce


You can check if a project like artagnon/ibex, which uses the go-imap package, does provide that feature.
See for instance its artagnon/ibex/imap.go#L288-L301 test.

var body []byte
cmd, err = imap.Wait(c.UIDFetch(set, "BODY.PEEK[]"))
if (err != nil) {
    fmt.Println(err.Error())
    return nil
}
body = imap.AsBytes(cmd.Data[0].MessageInfo().Attrs["BODY[]"])
cmd.Data = nil

bytestring, err := json.Marshal(MessageDetail{string(body)})
if (err != nil) {
    fmt.Println(err.Error())
    return nil
}
return bytestring
like image 42
VonC Avatar answered Sep 21 '22 21:09

VonC