1
0
mirror of https://github.com/jhillyerd/inbucket.git synced 2025-12-17 09:37:02 +00:00

Started work on MIME parser

I'm hoping to mostly rely on the official mime and mime/multipart
packages, but Inbucket is still going to have to decided what to
do with the various parts it reads.
This commit is contained in:
James Hillyerd
2012-10-14 23:11:39 -07:00
parent da8e0bc508
commit 46b123606b
3 changed files with 163 additions and 0 deletions

81
app/inbucket/mime.go Normal file
View File

@@ -0,0 +1,81 @@
package inbucket
import (
"bytes"
"fmt"
"io"
"mime"
"mime/multipart"
"net/mail"
)
const MIME_BUF_BYTES = 1024
type MIMEMessage struct {
text string
html string
}
func ParseMIMEMessage(mailMsg *mail.Message) (*MIMEMessage, error) {
mimeMsg := new(MIMEMessage)
// Parse top-level multipart
ctype := mailMsg.Header.Get("Content-Type")
mediatype, params, err := mime.ParseMediaType(ctype)
if err != nil {
return nil, err
}
switch mediatype {
case "multipart/alternative":
// Good
default:
return nil, fmt.Errorf("Unknown mediatype: %v", mediatype)
}
boundary := params["boundary"]
if boundary == "" {
return nil, fmt.Errorf("Unable to locate boundary param in Content-Type header")
}
// Buffer used by Part.Read to hand us chunks of data
readBytes := make([]byte, MIME_BUF_BYTES)
// Loop over MIME parts
mr := multipart.NewReader(mailMsg.Body, boundary)
for {
part, err := mr.NextPart()
if err != nil {
if err == io.EOF {
// This is a clean end-of-message signal
break
}
return nil, err
}
mediatype, params, err = mime.ParseMediaType(part.Header.Get("Content-Type"))
if err != nil {
return nil, err
}
if mediatype == "text/plain" && mimeMsg.text == "" {
// First text section, we'll have that, but first we have to deal with
// the odd way Part lets us read data.
var buf bytes.Buffer
for {
n, err := part.Read(readBytes)
if err != nil {
if err == io.EOF {
// Clean end of part signal
break
}
return nil, err
}
// Extra data in readBytes is not cleared, so we must respect
// the value returned in 'n'
buf.Write(readBytes[:n])
}
mimeMsg.text = buf.String()
fmt.Printf("text: '%v'\n", mimeMsg.text)
}
}
return mimeMsg, nil
}

28
app/inbucket/mime_test.go Normal file
View File

@@ -0,0 +1,28 @@
package inbucket
import (
"bufio"
"net/mail"
"os"
"testing"
)
func TestSomething(t *testing.T) {
// Open test email for parsing
raw, err := os.Open("../../test-data/html-mime-attach.raw")
if err != nil {
t.Fatalf("Failed to open test data: %v", err)
}
// Parse email into a mail.Message object like we do
reader := bufio.NewReader(raw)
msg, err := mail.ReadMessage(reader)
if err != nil {
t.Fatalf("Failed to read message: %v", err)
}
_, err = ParseMIMEMessage(msg)
if err != nil {
t.Fatalf("Failed to parse mime: %v", err)
}
}

View File

@@ -0,0 +1,54 @@
From: James Hillyerd <james@makita.skynet>
Content-Type: multipart/alternative; boundary="Apple-Mail=_E091454E-BCFA-43B4-99C0-678AEC9868D6"
Subject: MIME test 1
Date: Sat, 13 Oct 2012 15:33:07 -0700
Message-Id: <4E2E5A48-1A2C-4450-8663-D41B451DA93E@makita.skynet>
To: greg@nobody.com
Mime-Version: 1.0 (Apple Message framework v1283)
X-Mailer: Apple Mail (2.1283)
--Apple-Mail=_E091454E-BCFA-43B4-99C0-678AEC9868D6
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
charset=us-ascii
Test of HTML section
--Apple-Mail=_E091454E-BCFA-43B4-99C0-678AEC9868D6
Content-Type: multipart/related;
type="text/html";
boundary="Apple-Mail=_D2ABE25A-F0FE-404E-94EE-D98BD23448D5"
--Apple-Mail=_D2ABE25A-F0FE-404E-94EE-D98BD23448D5
Content-Transfer-Encoding: 7bit
Content-Type: text/html;
charset=us-ascii
<html><head></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><font class="Apple-style-span" face="'Comic Sans MS'">Test of HTML section</font><img height="16" width="16" apple-width="yes" apple-height="yes" id="4579722f-d53d-45d0-88bc-f8209a2ca569" src="cid:8B8481A2-25CA-4886-9B5A-8EB9115DD064@skynet"></body></html>
--Apple-Mail=_D2ABE25A-F0FE-404E-94EE-D98BD23448D5
Content-Transfer-Encoding: base64
Content-Disposition: inline;
filename=favicon.png
Content-Type: image/png;
x-unix-mode=0644;
name="favicon.png"
Content-Id: <8B8481A2-25CA-4886-9B5A-8EB9115DD064@skynet>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJ
bWFnZVJlYWR5ccllPAAAAlFJREFUeNqUU8tOFEEUPVVdNV3dPe8xYRBnjGhmBgKjKzCIiQvBoIaN
bly5Z+PSv3Aj7DSiP2B0rwkLGVdGgxITSCRIJGSMEQWZR3eVt5sEFBgTb/dN1yvnnHtPNTPG4Pqd
HgCMXnPRSZrpSuH8vUJu4DE4rYHDGAZDX62BZttHqTiIayM3gGiXQsgYLEvATaqxU+dy1U13YXap
XptpNHY8iwn8KyIAzm1KBdtRZWErpI5lEWTXp5Z/vHpZ3/wyKKwYGGOdAYwR0EZwoezTYApBEIOb
yELl/aE1/83cp40Pt5mxqCKrE4Ck+mVWKKcI5tA8BLEhRBKJLjez6a7MLq7XZtp+yyOawwCBtkiB
VZDKzRk4NN7NQBMYPHiZDFhXY+p9ff7F961vVcnl4R5I2ykJ5XFN7Ab7Gc61VoipNBKF+PDyztu5
lfrSLT/wIwCxq0CAGtXHZTzqR2jtwQiXONma6hHpj9sLT7YaPxfTXuZdBGA02Wi7FS48YiTfj+i2
NhqtdhP5RC8mh2/Op7y0v6eAcWVLFT8D7kWX5S9mepp+C450MV6aWL1cGnvkxbwHtLW2B9AOkLeU
d9KEDuh9fl/7CEj7YH5g+3r/lWfF9In7tPz6T4IIwBJOr1SJyIGQMZQbsh5P9uBq5VJtqHh2mo49
pdw5WFoEwKWqWHacaWOjQXWGcifKo6vj5RGS6zykI587XeUIQDqJSmAp+lE4qt19W5P9o8+Lma5D
cjsC8JiT607lMVkdqQ0Vyh3lHhmh52tfNy78ajXv0rgYzv8nfwswANuk+7sD/Q0aAAAAAElFTkSu
QmCC
--Apple-Mail=_D2ABE25A-F0FE-404E-94EE-D98BD23448D5--
--Apple-Mail=_E091454E-BCFA-43B4-99C0-678AEC9868D6--