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:
81
app/inbucket/mime.go
Normal file
81
app/inbucket/mime.go
Normal 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
28
app/inbucket/mime_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
54
test-data/html-mime-attach.raw
Normal file
54
test-data/html-mime-attach.raw
Normal 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--
|
||||
Reference in New Issue
Block a user