summaryrefslogtreecommitdiff
path: root/src/pkg/mail/message.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/mail/message.go')
-rw-r--r--src/pkg/mail/message.go95
1 files changed, 95 insertions, 0 deletions
diff --git a/src/pkg/mail/message.go b/src/pkg/mail/message.go
new file mode 100644
index 000000000..9723863fe
--- /dev/null
+++ b/src/pkg/mail/message.go
@@ -0,0 +1,95 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package mail implements parsing of mail messages according to RFC 5322.
+package mail
+
+import (
+ "bufio"
+ "io"
+ "net/textproto"
+ "os"
+ "time"
+)
+
+// A Message represents a parsed mail message.
+type Message struct {
+ Header Header
+ Body io.Reader
+}
+
+// ReadMessage reads a message from r.
+// The headers are parsed, and the body of the message will be reading from r.
+func ReadMessage(r io.Reader) (msg *Message, err os.Error) {
+ tp := textproto.NewReader(bufio.NewReader(r))
+
+ hdr, err := tp.ReadMIMEHeader()
+ if err != nil {
+ return nil, err
+ }
+
+ return &Message{
+ Header: Header(hdr),
+ Body: tp.R,
+ }, nil
+}
+
+// Layouts suitable for passing to time.Parse.
+// These are tried in order.
+var dateLayouts []string
+
+func init() {
+ // Generate layouts based on RFC 5322, section 3.3.
+
+ dows := [...]string{"", "Mon, "} // day-of-week
+ days := [...]string{"2", "02"} // day = 1*2DIGIT
+ years := [...]string{"2006", "06"} // year = 4*DIGIT / 2*DIGIT
+ seconds := [...]string{":05", ""} // second
+ zones := [...]string{"-0700", "MST"} // zone = (("+" / "-") 4DIGIT) / "GMT" / ...
+
+ for _, dow := range dows {
+ for _, day := range days {
+ for _, year := range years {
+ for _, second := range seconds {
+ for _, zone := range zones {
+ s := dow + day + " Jan " + year + " 15:04" + second + " " + zone
+ dateLayouts = append(dateLayouts, s)
+ }
+ }
+ }
+ }
+ }
+}
+
+func parseDate(date string) (*time.Time, os.Error) {
+ for _, layout := range dateLayouts {
+ t, err := time.Parse(layout, date)
+ if err == nil {
+ return t, nil
+ }
+ }
+ return nil, os.ErrorString("mail: header could not be parsed")
+}
+
+// TODO(dsymonds): Parsers for more specific headers such as To, From, etc.
+
+// A Header represents the key-value pairs in a mail message header.
+type Header map[string][]string
+
+// Get gets the first value associated with the given key.
+// If there are no values associated with the key, Get returns "".
+func (h Header) Get(key string) string {
+ return textproto.MIMEHeader(h).Get(key)
+}
+
+var ErrHeaderNotPresent = os.ErrorString("mail: header not in message")
+
+// Date parses the Date header field.
+func (h Header) Date() (*time.Time, os.Error) {
+ hdr := h.Get("Date")
+ if hdr == "" {
+ return nil, ErrHeaderNotPresent
+ }
+ return parseDate(hdr)
+}