Search code examples
emailgomimemultipart

Overlapped multipart 'no media type'


I'm trying to extract the body of the mail.

I made a function that I use when Content-Type has 'multipart'.

like this:

func multipartFunc(w http.ResponseWriter, content string) string {

 msg, err := mail.ReadMessage(bytes.NewBufferString(content))
 var uDec []byte 
 mediaType, params, err := mime.ParseMediaType(msg.Header.Get("Content-Type"))

if err != nil {
    log.Fatal("2 error: ", err)
}

if strings.HasPrefix(mediaType, "multipart/") {
    mr := multipart.NewReader(msg.Body, params["boundary"])
    for {
        p, err := mr.NextPart()
        if err == io.EOF {
            break
        }
        if err != nil {
            log.Fatal(err)
        }

        slurp, err := ioutil.ReadAll(p)
        if err != nil {
            log.Fatal(err)
        }
        encoding := p.Header.Get("Content-Transfer-Encoding\n")
        if encoding == "" {
            encoding = "7bit"
        }
        if strings.Contains(p.Header.Get("Content-Type"), "multipart") {
            newContent := "\nMime-Version: 1.0\n" + "Message-ID: " + randomString(12) + "\nContent-Type: " + p.Header.Get("Content-Type") + "\nContent-Transfer-Encoding: " + encoding + ";\n" + string(slurp)
            **ss := multipartFunc(w, newContent)**
            return ss
        }

        if p.Header.Get("Content-Transfer-Encoding") == "base64" {
            uDec, _ = base64.StdEncoding.DecodeString(string(slurp))
        } else if p.Header.Get("Content-Transfer-Encoding") == "quoted-printable" {
            uDec, _ = ioutil.ReadAll(quotedprintable.NewReader(strings.NewReader(string(slurp))))
        } else {
            uDec = []byte(string(slurp))
        }
    }
} 
return string(uDec)

Example mail:

 From: <aa@aa.or.kr>
 Date: Wed, 07 Oct 2020 09:25:49 +0900
 Message-Id: <RWAA4Q95VBU4.esdqwe@ds4>
 To: aa@aa.com
 MIME-Version: 1.0
 Content-Type: multipart/mixed; boundary="=-pm6oKFbVvZj4hXY1hoVA4g=="

 --=-pm6oKFbVvZj4hXY1hoVA4g==
 Content-Type: multipart/alternative; boundary="=-OM18H8UnjkvG1nNW6D77AQ=="

 --=-OM18H8UnjkvG1nNW6D77AQ==
 Content-Type: text/plain; charset=utf-8
 Content-Transfer-Encoding: base64

 DQoNCg0KCQ0KICAgICAgICAgICAgICAgIA


 --=-OM18H8UnjkvG1nNW6D77AQ==
 Content-Type: text/html; charset=utf-8
 Content-Transfer-Encoding: base64

 PGh0bWwgbGFuZz0ia28iPg0KPG1ldGEgYLTgiPg0KDQoJPGRpdiBpZD0i


 --=-OM18H8UnjkvG1nNW6D77AQ==--

 --=-pm6oKFbVvZj4hXY1hoVA4g==--

But If I extract part overlapped multipart and re-insert it, an error occurs. ('no media type' or 'malformed MIME header: missing colon: %!q')

I have no idea where the problem is.


Solution

  • You are creating a new message with:

    newContent := "\nMime-Version: 1.0\n" + "Message-ID: " + ...
    

    So an example message might be:

    
    Mime-Version: 1.0
    Message-ID: RANDOMSTRING
    

    This starts with a blank line and that is what separates the header from the message so when the message is parsed the header will be blank (you can see this by adding fmt.Printf("Header: %v\n", msg.Header) after calling mail.ReadMessage).

    Removing that \n results in another error (well that would happen if you checked the error - please remember to check after every call) malformed MIME header: missing colon: "--=-OM18H8UnjkvG1nNW6D77AQ==". This is because you did not add a blank line at the end of the headers. So you need to add another \n at the end.

    ... + encoding + ";\n\n" + string(slurp)
    

    Having done this the code runs see playground. Please note that I have only made the changes to get this running; I have not performed any further checks. I have left some debugging code in place (Printf) to show you how I went about tracing the issue (if you raise further issues posting a Minimal, Reproducible Example makes this process easier).