Golang mime/multipart library can be used to read and decode email messages.
I'm trying to make a proxy that is as transparent as possible, only changing those parts of message that it needs to.
Consider the input with a MIME part beginning
------=_Part_59911055_42259284.1503007218447
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
The below code fragment correctly sets the boundary and passes on the text/plain
part.
However pEncoding
is always read as the blank string ""
.
This would appear to be because of this
As a special case, if the "Content-Transfer-Encoding" header has a value of "quoted-printable", that header is instead hidden from this map and the body is transparently decoded during Read calls.
Is there a way to get the original value of the MIME part's Content-Transfer-Encoding?
// bodyCopy copies the mail message from msg to dst, with awareness of MIME parts.
// This is probably a naive implementation when it comes to complex multi-part messages and
// differing encodings.
func bodyCopy(dst io.Writer, msgHeader mail.Header, msgBody io.Reader) (int64, error) {
var bytesWritten int64
// Check Content-Type header - if not present, just copy mail through
cType := msgHeader.Get("Content-Type")
if cType == "" {
return partCopy(dst, msgBody) // Passthrough
}
// Check what MIME media type we have.
mediaType, params, err := mime.ParseMediaType(cType)
cEncoding := msgHeader.Get("Content-Transfer-Encoding")
log.Println(cEncoding)
if err != nil {
return bytesWritten, err
}
if strings.HasPrefix(mediaType, "text/plain") {
return partCopy(dst, msgBody) // Passthrough
}
if strings.HasPrefix(mediaType, "text/html") {
return htmlPartTransfer(dst, msgBody)
}
if strings.HasPrefix(mediaType, "multipart/") {
mr := multipart.NewReader(msgBody, params["boundary"])
for {
p, err := mr.NextPart()
if err != nil {
if err == io.EOF {
err = nil // change EOF (which is normal exit from this loop)
}
return bytesWritten, err // EOF (normal) or error
}
pType := p.Header.Get("Content-Type")
pEncoding := p.Header.Get("Content-Transfer-Encoding")
log.Println(pEncoding)
// TODO: need to handle various encodings of the parts
pWrt := multipart.NewWriter(dst)
pWrt.SetBoundary(params["boundary"])
pWrt2, err := pWrt.CreatePart(p.Header)
pWrt3 := quotedprintable.NewWriter(pWrt2) // Brute force method, converts everything back to QP. Don't want to do this!
bytesWritten, err := partCopy(pWrt3, p)
if err != nil {
return bytesWritten, err
}
log.Printf("\t\tContent-type: %s = %d bytes
", pType, bytesWritten)
}
}
return bytesWritten, err
}