1package mail 2 3import ( 4 "io" 5 "strings" 6 7 "github.com/emersion/go-message" 8) 9 10func initInlineContentTransferEncoding(h *message.Header) { 11 if !h.Has("Content-Transfer-Encoding") { 12 t, _, _ := h.ContentType() 13 if strings.HasPrefix(t, "text/") { 14 h.Set("Content-Transfer-Encoding", "quoted-printable") 15 } else { 16 h.Set("Content-Transfer-Encoding", "base64") 17 } 18 } 19} 20 21func initInlineHeader(h *InlineHeader) { 22 h.Set("Content-Disposition", "inline") 23 initInlineContentTransferEncoding(&h.Header) 24} 25 26func initAttachmentHeader(h *AttachmentHeader) { 27 disp, _, _ := h.ContentDisposition() 28 if disp != "attachment" { 29 h.Set("Content-Disposition", "attachment") 30 } 31 if !h.Has("Content-Transfer-Encoding") { 32 h.Set("Content-Transfer-Encoding", "base64") 33 } 34} 35 36// A Writer writes a mail message. A mail message contains one or more text 37// parts and zero or more attachments. 38type Writer struct { 39 mw *message.Writer 40} 41 42// CreateWriter writes a mail header to w and creates a new Writer. 43func CreateWriter(w io.Writer, header Header) (*Writer, error) { 44 header.Set("Content-Type", "multipart/mixed") 45 46 mw, err := message.CreateWriter(w, header.Header) 47 if err != nil { 48 return nil, err 49 } 50 51 return &Writer{mw}, nil 52} 53 54// CreateSingleInlineWriter writes a mail header to w. The mail will contain a 55// single inline part. The body of the part should be written to the returned 56// io.WriteCloser. Only one single inline part should be written, use 57// CreateWriter if you want multiple parts. 58func CreateSingleInlineWriter(w io.Writer, header Header) (io.WriteCloser, error) { 59 initInlineContentTransferEncoding(&header.Header) 60 return message.CreateWriter(w, header.Header) 61} 62 63// CreateInline creates a InlineWriter. One or more parts representing the same 64// text in different formats can be written to a InlineWriter. 65func (w *Writer) CreateInline() (*InlineWriter, error) { 66 var h message.Header 67 h.Set("Content-Type", "multipart/alternative") 68 69 mw, err := w.mw.CreatePart(h) 70 if err != nil { 71 return nil, err 72 } 73 return &InlineWriter{mw}, nil 74} 75 76// CreateSingleInline creates a new single text part with the provided header. 77// The body of the part should be written to the returned io.WriteCloser. Only 78// one single text part should be written, use CreateInline if you want multiple 79// text parts. 80func (w *Writer) CreateSingleInline(h InlineHeader) (io.WriteCloser, error) { 81 initInlineHeader(&h) 82 return w.mw.CreatePart(h.Header) 83} 84 85// CreateAttachment creates a new attachment with the provided header. The body 86// of the part should be written to the returned io.WriteCloser. 87func (w *Writer) CreateAttachment(h AttachmentHeader) (io.WriteCloser, error) { 88 initAttachmentHeader(&h) 89 return w.mw.CreatePart(h.Header) 90} 91 92// Close finishes the Writer. 93func (w *Writer) Close() error { 94 return w.mw.Close() 95} 96 97// InlineWriter writes a mail message's text. 98type InlineWriter struct { 99 mw *message.Writer 100} 101 102// CreatePart creates a new text part with the provided header. The body of the 103// part should be written to the returned io.WriteCloser. 104func (w *InlineWriter) CreatePart(h InlineHeader) (io.WriteCloser, error) { 105 initInlineHeader(&h) 106 return w.mw.CreatePart(h.Header) 107} 108 109// Close finishes the InlineWriter. 110func (w *InlineWriter) Close() error { 111 return w.mw.Close() 112} 113