func getSubject(msg *mail.Message) (string, error) { var dec mime.WordDecoder ret, err := dec.DecodeHeader(msg.Header.Get("Subject")) if err != nil { return "", err } return ret, nil }
// DecodeHeader (per RFC 2047) using Golang's mime.WordDecoder func DecodeHeader(input string) string { if !strings.Contains(input, "=?") { // Don't scan if there is nothing to do here return input } dec := new(mime.WordDecoder) dec.CharsetReader = NewCharsetReader header, err := dec.DecodeHeader(input) if err != nil { return input } return header }
// NonASCII Decode non ASCII header string RFC 1342 func NonASCII(encoded string) string { regexRFC1342, _ := regexp.Compile(`=\?.*?\?=`) dec := new(mime.WordDecoder) dec.CharsetReader = charset.NewReader result := regexRFC1342.ReplaceAllStringFunc(encoded, func(encoded string) string { decoded, err := dec.Decode(encoded) if err != nil { log.Println("Error decode NonASCII", encoded, err) return encoded } return decoded }) return result }
func parseAndDecodeHeader(rawMimeHeader textproto.MIMEHeader, target string, mHeader PMIMEHeader) string { if targetArray, ok := rawMimeHeader[target]; !ok && len(targetArray) == 0 { return "" } else { var ( encodedValue string = strings.TrimPrefix(targetArray[0], " ") decoded string dec *mime.WordDecoder = new(mime.WordDecoder) err error ) if decoded, err = dec.DecodeHeader(encodedValue); err != nil { fmt.Printf("[watney] WARNING: Couldn't decode string: \n\t%s\n\t%s\n", encodedValue, err.Error()) return encodedValue } return decoded } }
func ExampleWordDecoder_Decode() { dec := new(mime.WordDecoder) header, err := dec.Decode("=?utf-8?q?=C2=A1Hola,_se=C3=B1or!?=") if err != nil { panic(err) } fmt.Println(header) dec.CharsetReader = func(charset string, input io.Reader) (io.Reader, error) { switch charset { case "x-case": // Fake character set for example. // Real use would integrate with packages such // as code.google.com/p/go-charset content, err := ioutil.ReadAll(input) if err != nil { return nil, err } return bytes.NewReader(bytes.ToUpper(content)), nil default: return nil, fmt.Errorf("unhandled charset %q", charset) } } header, err = dec.Decode("=?x-case?q?hello!?=") if err != nil { panic(err) } fmt.Println(header) // Output: // ¡Hola, señor! // HELLO! }
func WordDecoder() *mime.WordDecoder { decoder := new(mime.WordDecoder) decoder.CharsetReader = CharsetReader return decoder }
// Parse parses a MIME encoded message. func Parse(r io.Reader) ( header *Header, subject string, message string, attachments []*Attachment, err error, ) { var h Header // read message msg, err := mail.ReadMessage(r) if err != nil { return nil, "", "", nil, log.Error(err) } // parse 'From' h.From = msg.Header.Get("From") if h.From == "" { return nil, "", "", nil, log.Error("mime: 'From' not defined") } // parse 'To' h.To = msg.Header.Get("To") if h.To == "" { return nil, "", "", nil, log.Error("mime: 'To' not defined") } // parse 'Cc' addressList, err := msg.Header.AddressList("Cc") if err != nil && err != mail.ErrHeaderNotPresent { return nil, "", "", nil, log.Error(err) } if err != mail.ErrHeaderNotPresent { for _, address := range addressList { h.Cc = append(h.Cc, address.Address) } } // parse subject subj := msg.Header.Get("Subject") if subj == "" { return nil, "", "", nil, log.Error("mime: 'Subject' not defined") } dec := new(mime.WordDecoder) subject, err = dec.DecodeHeader(subj) if err != nil { return nil, "", "", nil, log.Error(err) } // parse 'Message-ID' h.MessageID = msg.Header.Get("Message-ID") if h.MessageID == "" { return nil, "", "", nil, log.Error("mime: 'Message-ID' not defined") } // parse 'In-Reply-To' h.InReplyTo = msg.Header.Get("In-Reply-To") // parse 'MIME-Version' if msg.Header.Get("MIME-Version") != "1.0" { return nil, "", "", nil, log.Error("mime: wrong 'MIME-Version' header") } // parse 'Content-Type' mediaType, params, err := mime.ParseMediaType(msg.Header.Get("Content-Type")) if err != nil { return nil, "", "", nil, log.Error(err) } else if mediaType != "multipart/mixed" { return nil, "", "", nil, log.Error("mime: wrong 'Content-Type' header ") } // read first MIME part (message) mr := multipart.NewReader(msg.Body, params["boundary"]) p, err := mr.NextPart() if err != nil { return nil, "", "", nil, log.Error(err) } // check 'Content-Type' if p.Header.Get("Content-Type") != "text/plain" { return nil, "", "", nil, log.Error("mime: expected 'text/plain' Content-Type") } // check 'Content-Transfer-Encoding' if p.Header.Get("Content-Transfer-Encoding") != "base64" { return nil, "", "", nil, log.Error("mime: expected 'base64' Content-Transfer-Encoding") } // read message enc, err := ioutil.ReadAll(p) if err != nil { return nil, "", "", nil, log.Error(err) } content, err := base64.Decode(string(enc)) if err != nil { return nil, "", "", nil, log.Error(err) } message = string(content) // read optional additional MIME parts (attachments) for { p, err := mr.NextPart() if err == io.EOF { break } // parse header contentType := p.Header.Get("Content-Type") if contentType == "" { return nil, "", "", nil, log.Error("mime: Content-Type undefined for attachment") } var filename string var inline bool for _, disposition := range p.Header["Content-Disposition"] { mediaType, params, err := mime.ParseMediaType(disposition) if err != nil { return nil, "", "", nil, log.Error(err) } switch mediaType { case "attachment": filename = params["filename"] case "inline": inline = true default: return nil, "", "", nil, log.Errorf("mime: unknown Content-Disposition in attachment: %s", mediaType) } } if filename == "" { log.Error("mime: filename undefined for attachment") } // parse body if err != nil { return nil, "", "", nil, log.Error(err) } enc, err := ioutil.ReadAll(p) if err != nil { return nil, "", "", nil, log.Error(err) } content, err := base64.Decode(string(enc)) if err != nil { return nil, "", "", nil, log.Error(err) } // reconstruct attachment attachment := &Attachment{ Filename: filename, Reader: bytes.NewBuffer(content), ContentType: contentType, Inline: inline, } attachments = append(attachments, attachment) } header = &h return }