Exemplo n.º 1
0
func selectMultiPart(msg *mail.Message, boundary, preferType string) (*mail.Message, error) {
	reader := multipart.NewReader(msg.Body, boundary)
	parts := make(map[string]*mail.Message)
	for part, err := reader.NextPart(); err != io.EOF; part, err = reader.NextPart() {
		if err != nil {
			return nil, err
		}
		header := mail.Header(part.Header)
		mediatype, _, err := mime.ParseMediaType(header.Get("Content-Type"))
		if err != nil {
			continue
		}
		if mediatype == preferType {
			return &mail.Message{header, part}, nil
		}
		types := strings.Split(mediatype, "/")
		if len(types) == 0 {
			continue
		}
		if _, ok := parts[types[0]]; !ok {
			body, err := ioutil.ReadAll(part)
			if err == nil {
				parts[types[0]] = &mail.Message{header, bytes.NewBuffer(body)}
			}
		}
	}
	types := strings.Split(preferType, "/")
	if part, ok := parts[types[0]]; ok {
		return part, nil
	}
	if part, ok := parts["multipart"]; ok {
		return part, nil
	}
	return nil, fmt.Errorf("No prefered part")
}
Exemplo n.º 2
0
func TestMailAddress(t *testing.T) {
	Log.SetHandler(tsthlp.TestHandler(t))

	for i, str := range [][3]string{
		[3]string{"=?iso-8859-2?Q?Bogl=E1rka_Tak=E1cs?= <*****@*****.**>",
			"Boglárka Takács", "<*****@*****.**>"},
		[3]string{"=?iso-8859-2?Q?K=E1r_Oszt=E1ly_=28kar=40kobe=2Ehu=29?= <*****@*****.**>",
			"Kár_Osztály [email protected]", "<*****@*****.**>"},
	} {
		mh := make(map[string][]string, 1)
		k := strconv.Itoa(i)
		mh[k] = []string{str[0]}
		mailHeader := mail.Header(mh)
		if addr, err := mailHeader.AddressList(k); err == nil {
			t.Errorf("address for %s: %q", k, addr)
		} else {
			t.Logf("error parsing address %s(%q): %s", k, mailHeader.Get(k), err)
		}
		if addr, err := ParseAddress(str[0]); err != nil {
			t.Errorf("error parsing address %q: %s", str[0], err)
		} else {
			t.Logf("address for %q: %q <%s>", str[0], addr.Name, addr.Address)
		}
	}
}
Exemplo n.º 3
0
func TestParseQuotedBody(t *testing.T) {

	header := mail.Header(map[string][]string{
		"Content-Type":              []string{"text/html; charset=\"iso-8859-1\""},
		"Content-Transfer-Encoding": []string{"quoted-printable"},
	})
	html, text, multipart, err := parseBody(header, []byte(quotedEmail))
	if err != nil {
		t.Error("error doing test! ", err)
		return
	}

	if multipart {
		t.Error("parse body returned with multipart flag set")
	}

	if len(text) > 0 {
		t.Errorf("an HTML only email returned with text: %q", string(text))
	}

	if bytes.Contains(html, []byte("=3D")) {
		t.Errorf("parseBody did not handle quoted-printable format as expected. `=3D' still found in message:\n%q", string(html))
	}

	// crazy Äpple to verify we parsed iso-8859-1 correctly AND did the quoted-printable fix
	if !bytes.HasPrefix(html, []byte("Äpple<html><head>")) || !bytes.HasSuffix(html, []byte("</html>\r\n")) {
		t.Errorf("parseBody did not pull out HTML correctly. Expected '<html><head>' prefix and '</html>\r\n' suffix. got:\n%q", string(html))
	}
}
Exemplo n.º 4
0
func (h ciHeader) AddressList(key string) ([]*mail.Address, error) {
	header := mail.Header(h)

	// First try with stdlib implementation
	addresses, err := header.AddressList(key)
	if err == nil {
		return addresses, nil
	}

	value, found := header[key]
	if !found {
		return nil, nil
	}

	// "Forced" parsing of non-standard e-mail addresses
	return h.parseNonstandardAddressesList(strings.Join(value, " "))
}
Exemplo n.º 5
0
// Header returns the corresponding mail header to a key.
func (d Dir) Header(key string) (header mail.Header, err error) {
	filename, err := d.Filename(key)
	if err != nil {
		return
	}
	file, err := os.Open(filename)
	if err != nil {
		return
	}
	defer file.Close()
	tp := textproto.NewReader(bufio.NewReader(file))
	hdr, err := tp.ReadMIMEHeader()
	if err != nil {
		return
	}
	header = mail.Header(hdr)
	return
}
Exemplo n.º 6
0
func TestParseMultiBody(t *testing.T) {
	header := mail.Header(map[string][]string{"Content-Type": []string{`multipart/alternative; boundary="eZDakj4l4DVQ=_?:"`}})
	html, text, multipart, err := parseBody(header, []byte(multipartEmail))
	if err != nil {
		t.Error("error doing test! ", err)
		return
	}

	if !multipart {
		t.Error("parse body did not return with multipart flag set")
	}

	if !bytes.HasPrefix(html, []byte("<!DOCTYPE html>")) || !bytes.HasSuffix(html, []byte("</html>\n")) {
		t.Errorf("parseBody did not pull out the HTML correctly. Expected to start with doctype and end with </html>, got:\n%q", string(html))
	}

	if !bytes.HasPrefix(text, []byte("NBA announces")) || !bytes.HasSuffix(text, []byte("approved Ballmer.\n")) {
		t.Errorf("parseBody did not pull out text correctly. Expected 'NBA announces' prefix and 'Ballmer.' suffix. got:\n%q", string(text))
	}
}
Exemplo n.º 7
0
func TestParsePlainBody(t *testing.T) {
	header := mail.Header(map[string][]string{"Content-Type": []string{"text/html; charset=UTF-8"}})
	html, text, multipart, err := parseBody(header, []byte(htmlEmail))
	if err != nil {
		t.Error("error doing test! ", err)
		return
	}

	if multipart {
		t.Error("parse body returned with multipart flag set")
	}

	if len(text) > 0 {
		t.Errorf("an HTML only email returned with text: %q", string(text))
	}

	if !bytes.HasPrefix(html, []byte("<br />")) || !bytes.HasSuffix(html, []byte("FoxNews.com.")) {
		t.Errorf("parseBody did not pull out HTML correctly. Expected '<br />' prefix and 'FoxNews.com.' suffix. got:\n%q", string(html))
	}
}
Exemplo n.º 8
0
func compose() (*mail.Message, error) {
	// Make sure we can re-use Stdin even after being consumed by mail.ReadMessage
	b := bytes.Buffer{}
	b.ReadFrom(os.Stdin)
	msg := b.String()

	m, err := mail.ReadMessage(bytes.NewBufferString(msg))
	if err != nil {
		if config.ScanMessage {
			return nil, fmt.Errorf("ScanMessage: cannot parse message: %s", err)
		}

		// Assume there are no headers in the message
		m = &mail.Message{
			Header: mail.Header(textproto.MIMEHeader{}),
			Body:   bufio.NewReader(bytes.NewBufferString(msg)),
		}
	}

	// Make sure all required fields are set
	if 0 == len(m.Header["From"]) {
		m.Header["From"] = []string{(&mail.Address{config.Message_FromName, config.Message_From}).String()}
	} else if from, err := mail.ParseAddress(m.Header["From"][0]); config.ScanMessage && err == nil {
		// Parse and put in config; to be used by c.Mail
		config.Message_From = from.Address
	}

	if 0 == len(m.Header["To"]) {
		m.Header["To"] = config.Message_To
	}

	if 0 == len(m.Header["Date"]) {
		m.Header["Date"] = []string{time.Now().Format("Mon, 2 Jan 2006 15:04:05 -0700")}
	}

	if 0 == len(m.Header["Message-Id"]) {
		m.Header["Message-Id"] = []string{"<GOSSMTP." + generateMessageId() + "@" + config.Hostname + ">"}
	}

	return m, nil
}
Exemplo n.º 9
0
func (c *IMAPClient) GetMessage(id string) (*mail.Message, error) {
	headerResp := c.Do(fmt.Sprintf("FETCH %s %s", id, RFC822Header))
	if headerResp.Error() != nil {
		return nil, headerResp.Error()
	}

	replys := headerResp.Replys()

	reader := textproto.NewReader(bufio.NewReader(bytes.NewBuffer(replys[0].content)))
	header, err := reader.ReadMIMEHeader()
	if err != nil {
		return nil, err
	}

	bodyResp := c.Do(fmt.Sprintf("FETCH %s %s", id, RFC822Text))
	if bodyResp.Error() != nil {
		return nil, bodyResp.Error()
	}

	return &mail.Message{
		Header: mail.Header(header),
		Body:   bytes.NewBuffer(bodyResp.Replys()[0].content),
	}, nil
}
Exemplo n.º 10
0
func TestSelectPart(t *testing.T) {
	{
		hs := `MIME-Version: 1.0
Received: by 10.76.101.172 with HTTP; Tue, 26 Jun 2012 23:11:28 -0700 (PDT)
Date: Wed, 27 Jun 2012 14:11:28 +0800
Delivered-To: [email protected]
Message-ID: <*****@*****.**>
Subject: test
From: Googol Lee <*****@*****.**>
To: =?UTF-8?B?R29vZ29sIExlZSAtIEdvb2dsZee6r+eIt+S7rO+8gemTgeihgOecn+axieWtkO+8ge+8gQ==?= <*****@*****.**>
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: base64`
		bd := `YTAwNyBPSyBTdWNjZXNzCgopCgotLQrmlrDnmoTnkIborrrku47lsJHmlbDkurrnmoTkuLvlvKDl
iLDkuIDnu5/lpKnkuIvvvIzlubbkuI3mmK/lm6DkuLrov5nkuKrnkIborrror7TmnI3kuobliKvk
urrmipvlvIPml6fop4LngrnvvIzogIzmmK/lm6DkuLrkuIDku6PkurrnmoTpgJ3ljrvjgIIK`
		reader := textproto.NewReader(bufio.NewReader(bytes.NewBufferString(hs)))
		hr, _ := reader.ReadMIMEHeader()
		msg := &mail.Message{
			Header: mail.Header(hr),
			Body:   bytes.NewBufferString(bd),
		}

		expect := "a007 OK Success\n\n)\n\n--\n新的理论从少数人的主张到一统天下,并不是因为这个理论说服了别人抛弃旧观点,而是因为一代人的逝去。\n"
		content, mediatype, charset, _ := GetBody(msg, "text/plain")
		if mediatype != "text/plain" {
			t.Errorf("mediatype expect: text/plain, got: %s", mediatype)
		}
		if charset != "UTF-8" {
			t.Errorf("charset expect: UTF-8, got: %s", charset)
		}
		if content != expect {
			t.Errorf("content expect:\n%s\ngot:\n%s", expect, content)
		}
	}

	{
		hs := `MIME-Version: 1.0
Received: by 10.76.101.172 with HTTP; Tue, 26 Jun 2012 23:11:28 -0700 (PDT)
Date: Wed, 27 Jun 2012 14:11:28 +0800
Delivered-To: [email protected]
Message-ID: <*****@*****.**>
Subject: test
From: Googol Lee <*****@*****.**>
To: =?UTF-8?B?R29vZ29sIExlZSAtIEdvb2dsZee6r+eIt+S7rO+8gemTgeihgOecn+axieWtkO+8ge+8gQ==?= <*****@*****.**>
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable`
		bd := "If you believe that truth=3Dbeauty, then surely =\r\nmathematics is the most beautiful branch of philosophy."
		reader := textproto.NewReader(bufio.NewReader(bytes.NewBufferString(hs)))
		hr, _ := reader.ReadMIMEHeader()
		msg := &mail.Message{
			Header: mail.Header(hr),
			Body:   bytes.NewBufferString(bd),
		}

		expect := "If you believe that truth=beauty, then surely mathematics is the most beautiful branch of philosophy."
		content, mediatype, charset, _ := GetBody(msg, "text/plain")
		if mediatype != "text/plain" {
			t.Errorf("mediatype expect: text/plain, got: %s", mediatype)
		}
		if charset != "UTF-8" {
			t.Errorf("charset expect: UTF-8, got: %s", charset)
		}
		if content != expect {
			t.Errorf("content expect:\n%s\ngot:\n%s", expect, content)
		}
	}

	{
		hs := `MIME-Version: 1.0
Received: by 10.76.101.172 with HTTP; Tue, 26 Jun 2012 23:11:28 -0700 (PDT)
Date: Wed, 27 Jun 2012 14:11:28 +0800
Delivered-To: [email protected]
Message-ID: <*****@*****.**>
Subject: test
From: Googol Lee <*****@*****.**>
To: =?UTF-8?B?R29vZ29sIExlZSAtIEdvb2dsZee6r+eIt+S7rO+8gemTgeihgOecn+axieWtkO+8ge+8gQ==?= <*****@*****.**>
Content-Type: multipart/alternative; boundary=14dae9d67df4436caa04c39ae8b8`
		bd := `--14dae9d67df4436caa04c39ae8b8
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: base64

YWJjYWJjCgotLSAK5paw55qE55CG6K665LuO5bCR5pWw5Lq655qE5Li75byg5Yiw5LiA57uf5aSp
5LiL77yM5bm25LiN5piv5Zug5Li66L+Z5Liq55CG6K666K+05pyN5LqG5Yir5Lq65oqb5byD5pen
6KeC54K577yM6ICM5piv5Zug5Li65LiA5Luj5Lq655qE6YCd5Y6744CCCg==
--14dae9d67df4436caa04c39ae8b8
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: base64

YWJjYWJjPGJyPjxicj4tLSA8YnI+5paw55qE55CG6K665LuO5bCR5pWw5Lq655qE5Li75byg5Yiw
5LiA57uf5aSp5LiL77yM5bm25LiN5piv5Zug5Li66L+Z5Liq55CG6K666K+05pyN5LqG5Yir5Lq6
5oqb5byD5pen6KeC54K577yM6ICM5piv5Zug5Li65LiA5Luj5Lq655qE6YCd5Y6744CCPGJyPgo=
--14dae9d67df4436caa04c39ae8b8--`
		reader := textproto.NewReader(bufio.NewReader(bytes.NewBufferString(hs)))
		hr, _ := reader.ReadMIMEHeader()
		msg := &mail.Message{
			Header: mail.Header(hr),
			Body:   bytes.NewBufferString(bd),
		}

		expect := "abcabc\n\n-- \n新的理论从少数人的主张到一统天下,并不是因为这个理论说服了别人抛弃旧观点,而是因为一代人的逝去。\n"
		content, mediatype, charset, _ := GetBody(msg, "text/plain")
		if mediatype != "text/plain" {
			t.Errorf("mediatype expect: text/plain, got: %s", mediatype)
		}
		if charset != "UTF-8" {
			t.Errorf("charset expect: UTF-8, got: %s", charset)
		}
		if content != expect {
			t.Errorf("content expect:\n%s\ngot:\n%s", expect, content)
		}
	}

	{
		hs := `MIME-Version: 1.0
Received: by 10.76.101.172 with HTTP; Tue, 26 Jun 2012 23:11:28 -0700 (PDT)
Date: Wed, 27 Jun 2012 14:11:28 +0800
Delivered-To: [email protected]
Message-ID: <*****@*****.**>
Subject: test
From: Googol Lee <*****@*****.**>
To: =?UTF-8?B?R29vZ29sIExlZSAtIEdvb2dsZee6r+eIt+S7rO+8gemTgeihgOecn+axieWtkO+8ge+8gQ==?= <*****@*****.**>
Content-Type: multipart/alternative; boundary=14dae9d67df4436caa04c39ae8b8`
		bd := `--14dae9d67df4436caa04c39ae8b8
Content-Type: text/json; charset=UTF-8
Content-Transfer-Encoding: base64

YWJjYWJjCgotLSAK5paw55qE55CG6K665LuO5bCR5pWw5Lq655qE5Li75byg5Yiw5LiA57uf5aSp
5LiL77yM5bm25LiN5piv5Zug5Li66L+Z5Liq55CG6K666K+05pyN5LqG5Yir5Lq65oqb5byD5pen
6KeC54K577yM6ICM5piv5Zug5Li65LiA5Luj5Lq655qE6YCd5Y6744CCCg==
--14dae9d67df4436caa04c39ae8b8
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: base64

YWJjYWJjPGJyPjxicj4tLSA8YnI+5paw55qE55CG6K665LuO5bCR5pWw5Lq655qE5Li75byg5Yiw
5LiA57uf5aSp5LiL77yM5bm25LiN5piv5Zug5Li66L+Z5Liq55CG6K666K+05pyN5LqG5Yir5Lq6
5oqb5byD5pen6KeC54K577yM6ICM5piv5Zug5Li65LiA5Luj5Lq655qE6YCd5Y6744CCPGJyPgo=
--14dae9d67df4436caa04c39ae8b8--`
		reader := textproto.NewReader(bufio.NewReader(bytes.NewBufferString(hs)))
		hr, _ := reader.ReadMIMEHeader()
		msg := &mail.Message{
			Header: mail.Header(hr),
			Body:   bytes.NewBufferString(bd),
		}

		expect := "abcabc\n\n-- \n新的理论从少数人的主张到一统天下,并不是因为这个理论说服了别人抛弃旧观点,而是因为一代人的逝去。\n"
		content, mediatype, charset, _ := GetBody(msg, "text/plain")
		if mediatype != "text/json" {
			t.Errorf("mediatype expect: text/plain, got: %s", mediatype)
		}
		if charset != "UTF-8" {
			t.Errorf("charset expect: UTF-8, got: %s", charset)
		}
		if content != expect {
			t.Errorf("content expect:\n%s\ngot:\n%s", expect, content)
		}
	}
}
Exemplo n.º 11
0
// returns the content-type, params and a decoder for the body of the multipart
func getCT(
	header map[string][]string,
) (
	contentType string,
	params map[string]string,
	decoder func(io.Reader) io.Reader,
	err error,
) {
	decoder = func(r io.Reader) io.Reader {
		return r
	}
	contentType = mail.Header(header).Get("Content-Type")
	if contentType == "" {
		return
	}
	var nct string
	nct, params, err = mime.ParseMediaType(contentType)
	if err != nil {
		err = errgo.Newf("cannot parse Content-Type %s: %s", contentType, err)
		return
	}
	contentType = nct
	te := strings.ToLower(mail.Header(header).Get("Content-Transfer-Encoding"))
	switch te {
	case "":
	case "base64":
		decoder = func(r io.Reader) io.Reader {
			r = B64FilterReader(r, nil)
			if CheckEncoding {
				raw, e := ioutil.ReadAll(r)
				if e != nil {
					logger.Warn("msg", "cannot read data", "error", e)
					return bytes.NewReader(nil)
				}
				decoded := make([]byte, base64.StdEncoding.DecodedLen(len(raw)))
				n, e := base64.StdEncoding.Decode(decoded, raw)
				if e != nil {
					bad := string(raw[:min(20, len(raw))])
					txt := e.Error()
					q := strings.LastIndex(txt, " ")
					if q >= 0 {
						p, e2 := strconv.Atoi(txt[q+1:])
						if e2 == nil {
							p = max(0, p-4)
							q = min(len(raw), p+4)
							bad = string(raw[p:q])
						}
					}
					logger.Error("msg", "base64 decoding", "raw", bad, "error", e)
				}
				// K-MT9461
				return bytes.NewReader(decoded[:n])
			}
			return base64.NewDecoder(base64.StdEncoding, r)
		}
	case "quoted-printable":
		decoder = func(r io.Reader) io.Reader {
			br := bufio.NewReaderSize(r, 1024)
			first, _ := br.Peek(1024)
			enc := qprintable.BinaryEncoding
			if len(first) > 0 {
				enc = qprintable.DetectEncoding(string(first))
			}
			return qprintable.NewDecoder(enc, br)
		}
	default:
		logger.Warn("msg", "unknown transfer-encoding", "transfer-encoding", te)
	}
	return
}
Exemplo n.º 12
0
// PrependHeaderFilter writes Subject, From... headers at the beginning of the html/plain parts.
func PrependHeaderFilter(inch <-chan i18nmail.MailPart, outch chan<- i18nmail.MailPart,
	files chan<- ArchFileItem, errch chan<- error, ctx *Context,
) {
	defer func() {
		logger.Debug("msg", "PrependHeaderFilter closes", "outch", outch)
		close(outch)
	}()
	ctx = prepareContext(ctx, "")

	mailHeader := mail.Header(make(map[string][]string, len(PrependHeaders)))
	headersBuf := bytes.NewBuffer(make([]byte, 0, 128))
	var br *bufio.Reader

	for part := range inch {
		logger.Debug("msg", "PrependHeaderFilter receives", "seq", part.Seq, "ct", part.ContentType, "header", part.Header, "inch", inch)
		if len(mailHeader["From"]) == 0 || mailHeader["Subject"][0] == "" {
			hdrs := make([]textproto.MIMEHeader, 0, 4)
			parent := &part
			if len(parent.Header) > 0 {
				hdrs = append(hdrs, parent.Header)
			}
			for parent.Parent != nil {
				parent = parent.Parent
				if len(parent.Header) > 0 {
					hdrs = append(hdrs, parent.Header)
				}
			}
			if len(hdrs) > 0 {
				hdr := hdrs[len(hdrs)-1]
				logger.Info("msg", "filling mailHeader", "header", hdr)
				for _, k := range PrependHeaders {
					if v, ok := hdr[k]; ok {
						mailHeader[k] = v
					}
				}
			}
		}

		if !(part.ContentType == "text/plain" || part.ContentType == "text/html") {
			goto Skip
		}
		headersBuf.Reset()
		if err := writeHeaders(headersBuf, mailHeader, part.ContentType); err != nil {
			logger.Warn("msg", "error writing headers", "error", err)
			goto Skip
		}

		br = bufio.NewReader(part.Body)
		part.Body = br
		if part.ContentType == "text/html" {
			first, err := br.Peek(br.Buffered())
			if err != nil {
				logger.Warn("msg", "cannot read", "source", br, "error", err)
				goto Skip
			}
			if i := bytes.Index(first, []byte("<body>")); i >= 0 {
				part.Body = io.MultiReader(
					&io.LimitedReader{R: br, N: int64(i)},
					bytes.NewReader(headersBuf.Bytes()),
					bytes.NewReader(first[i:]),
					br,
				)
			} else {
				part.Body = io.MultiReader(bytes.NewReader(headersBuf.Bytes()), br)
			}
		} else {
			part.Body = io.MultiReader(bytes.NewReader(headersBuf.Bytes()), part.Body)
		}

	Skip:
		outch <- part
	}
}
Exemplo n.º 13
0
func (h ciHeader) Date() (time.Time, error) {
	return mail.Header(h).Date()
}
Exemplo n.º 14
0
func analyzeEmail(n *models.EmailNode, input []byte) error {
	// Figure out if newlines are \n or \r\n
	var nl []byte
	firstNewline := bytes.Index(input, []byte("\n"))
	if firstNewline-1 >= 0 && input[firstNewline-1] == '\r' {
		nl = []byte("\r\n")
	} else {
		nl = []byte("\n")
	}
	doubleNl := append(nl, nl...)

	// Parse the header
	tp := textproto.NewReader(bufio.NewReader(bytes.NewReader(input)))
	headers, err := tp.ReadMIMEHeader()
	if err != nil {
		return err
	}
	n.Headers = mail.Header(headers)

	// Calculate where the parts are
	seperator := bytes.Index(input, doubleNl)
	n.HeaderPosition = [2]int{n.BasePosition, n.BasePosition + seperator + len(nl)}
	n.BodyPosition = [2]int{n.BasePosition + seperator + len(nl), n.BasePosition + len(input)}

	// Check if the node is multipart
	ctype := headers.Get("Content-Type")
	if ctype == "" {
		ctype = "text/plain"
	}
	media, params, err := mime.ParseMediaType(ctype)
	if err != nil {
		return err
	}
	if !strings.HasPrefix(media, "multipart/") {
		return nil
	}
	if _, ok := params["boundary"]; !ok {
		return nil
	}

	// Prepare children slice
	n.Children = []*models.EmailNode{}

	// Prepare byte slices for comparsion
	var (
		dashBoundaryDashNl = []byte("--" + params["boundary"] + "--" + string(nl))
		dashBoundaryDash   = dashBoundaryDashNl[:len(dashBoundaryDashNl)-2]
		dashBoundaryNl     = []byte("--" + params["boundary"] + string(nl))
	)

	// Analyze where the multipart body starts
	start := bytes.Index(input, dashBoundaryNl)
	end := bytes.Index(input, dashBoundaryDashNl)
	if end == -1 {
		end = bytes.Index(input, dashBoundaryDash)
	}

	// Trim the data to only get the body without the wrappers
	bodyBaseIndex := n.BasePosition + start + len(dashBoundaryNl)
	partsData := input[start+len(dashBoundaryNl) : end]

	// Split the parts into multipart body parts
	for _, part := range bytes.Split(partsData, dashBoundaryNl) {
		np := &models.EmailNode{
			BasePosition: bodyBaseIndex,
		}

		if err := analyzeEmail(np, part); err != nil {
			return err
		}

		bodyBaseIndex += len(part) + len(dashBoundaryNl)

		n.Children = append(n.Children, np)
	}

	return nil
}
Exemplo n.º 15
0
// recursivley parse a multipart.Part
// will always return a *MessageNode, even on encountering errors. You will need
// good switching code to work with message nodes
// If errors occur whilst creating the sub-tree, such errors will be
// returned in a ChildError mapping. You may ignore such errors for the most
func MessageToNode(msg *mail.Message) (*MessageNode, error) {

	debug("starting message to node for message: ", msg)
	body, backup := backupReader(msg.Body)

	node := &MessageNode{
		Header: msg.Header,
		Body:   backup,
	}

	ct, params, err := mime.ParseMediaType(msg.Header.Get(ContentType))

	if err == nil {
		node.ContentType = ct
		node.ContentTypeParams = params
		if boundry, ok := params[Boundary]; ok {
			// parse the data as a multipart!

			multi := multipart.NewReader(body, boundry)
			child_err_occured := false
			child_errs := make(ChildError)
			node.Children = make([]*MessageNode, 0, 5)

			// read new Parts off the multipart parser
			for part, err := multi.NextPart(); err != io.EOF; part, err = multi.NextPart() {
				// check errors
				if err != nil {
					debug("error occured while making part: ", part, " error: ", err)
					// restore backup and abort parsing
					return node, fmt.Errorf("Aborted Multipart#NextPart at error: %v", err)
				}

				// create message so we can recurse
				sub_msg := &mail.Message{
					Header: mail.Header(part.Header),
					Body:   NewMarshalReader(part),
				}

				// create child node
				child, err := MessageToNode(sub_msg)

				// store any errors
				if err != nil {
					child_err_occured = true
					child_errs[child] = err
				}

				// store child
				node.Children = append(node.Children, child)
			} // end enumerate parts

			// don't need this data anymore, since we have the children
			node.Body = nil

			if child_err_occured {
				return node, child_errs
			}
		} // end has-boundry-parse-sections
	} // end decoded-mime-type

	if node.Body != nil {
		// make sure body has text export type
		// so the browser doesn't have to do MIME detection
		node.Body.MarshalAsString = IsText(node)
	}
	return node, nil
}
Exemplo n.º 16
0
// AddressList parses the named header field as a list of addresses.
func (h Header) AddressList(key string) ([]*mail.Address, error) {
	return mail.Header(h).AddressList(key)
}