Initialize module and dependencies
This commit is contained in:
42
vendor/github.com/emersion/go-message/mail/address.go
generated
vendored
Normal file
42
vendor/github.com/emersion/go-message/mail/address.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
package mail
|
||||
|
||||
import (
|
||||
"mime"
|
||||
"net/mail"
|
||||
"strings"
|
||||
|
||||
"github.com/emersion/go-message"
|
||||
)
|
||||
|
||||
// Address represents a single mail address.
|
||||
// The type alias ensures that a net/mail.Address can be used wherever an
|
||||
// Address is expected
|
||||
type Address = mail.Address
|
||||
|
||||
func formatAddressList(l []*Address) string {
|
||||
formatted := make([]string, len(l))
|
||||
for i, a := range l {
|
||||
formatted[i] = a.String()
|
||||
}
|
||||
return strings.Join(formatted, ", ")
|
||||
}
|
||||
|
||||
// ParseAddress parses a single RFC 5322 address, e.g. "Barry Gibbs <bg@example.com>"
|
||||
// Use this function only if you parse from a string, if you have a Header use
|
||||
// Header.AddressList instead
|
||||
func ParseAddress(address string) (*Address, error) {
|
||||
parser := mail.AddressParser{
|
||||
&mime.WordDecoder{message.CharsetReader},
|
||||
}
|
||||
return parser.Parse(address)
|
||||
}
|
||||
|
||||
// ParseAddressList parses the given string as a list of addresses.
|
||||
// Use this function only if you parse from a string, if you have a Header use
|
||||
// Header.AddressList instead
|
||||
func ParseAddressList(list string) ([]*Address, error) {
|
||||
parser := mail.AddressParser{
|
||||
&mime.WordDecoder{message.CharsetReader},
|
||||
}
|
||||
return parser.ParseList(list)
|
||||
}
|
||||
30
vendor/github.com/emersion/go-message/mail/attachment.go
generated
vendored
Normal file
30
vendor/github.com/emersion/go-message/mail/attachment.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
package mail
|
||||
|
||||
import (
|
||||
"github.com/emersion/go-message"
|
||||
)
|
||||
|
||||
// An AttachmentHeader represents an attachment's header.
|
||||
type AttachmentHeader struct {
|
||||
message.Header
|
||||
}
|
||||
|
||||
// Filename parses the attachment's filename.
|
||||
func (h *AttachmentHeader) Filename() (string, error) {
|
||||
_, params, err := h.ContentDisposition()
|
||||
|
||||
filename, ok := params["filename"]
|
||||
if !ok {
|
||||
// Using "name" in Content-Type is discouraged
|
||||
_, params, err = h.ContentType()
|
||||
filename = params["name"]
|
||||
}
|
||||
|
||||
return filename, err
|
||||
}
|
||||
|
||||
// SetFilename formats the attachment's filename.
|
||||
func (h *AttachmentHeader) SetFilename(filename string) {
|
||||
dispParams := map[string]string{"filename": filename}
|
||||
h.SetContentDisposition("attachment", dispParams)
|
||||
}
|
||||
381
vendor/github.com/emersion/go-message/mail/header.go
generated
vendored
Normal file
381
vendor/github.com/emersion/go-message/mail/header.go
generated
vendored
Normal file
@@ -0,0 +1,381 @@
|
||||
package mail
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/mail"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/emersion/go-message"
|
||||
)
|
||||
|
||||
const dateLayout = "Mon, 02 Jan 2006 15:04:05 -0700"
|
||||
|
||||
type headerParser struct {
|
||||
s string
|
||||
}
|
||||
|
||||
func (p *headerParser) len() int {
|
||||
return len(p.s)
|
||||
}
|
||||
|
||||
func (p *headerParser) empty() bool {
|
||||
return p.len() == 0
|
||||
}
|
||||
|
||||
func (p *headerParser) peek() byte {
|
||||
return p.s[0]
|
||||
}
|
||||
|
||||
func (p *headerParser) consume(c byte) bool {
|
||||
if p.empty() || p.peek() != c {
|
||||
return false
|
||||
}
|
||||
p.s = p.s[1:]
|
||||
return true
|
||||
}
|
||||
|
||||
// skipSpace skips the leading space and tab characters.
|
||||
func (p *headerParser) skipSpace() {
|
||||
p.s = strings.TrimLeft(p.s, " \t")
|
||||
}
|
||||
|
||||
// skipCFWS skips CFWS as defined in RFC5322. It returns false if the CFWS is
|
||||
// malformed.
|
||||
func (p *headerParser) skipCFWS() bool {
|
||||
p.skipSpace()
|
||||
|
||||
for {
|
||||
if !p.consume('(') {
|
||||
break
|
||||
}
|
||||
|
||||
if _, ok := p.consumeComment(); !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
p.skipSpace()
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *headerParser) consumeComment() (string, bool) {
|
||||
// '(' already consumed.
|
||||
depth := 1
|
||||
|
||||
var comment string
|
||||
for {
|
||||
if p.empty() || depth == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
if p.peek() == '\\' && p.len() > 1 {
|
||||
p.s = p.s[1:]
|
||||
} else if p.peek() == '(' {
|
||||
depth++
|
||||
} else if p.peek() == ')' {
|
||||
depth--
|
||||
}
|
||||
|
||||
if depth > 0 {
|
||||
comment += p.s[:1]
|
||||
}
|
||||
|
||||
p.s = p.s[1:]
|
||||
}
|
||||
|
||||
return comment, depth == 0
|
||||
}
|
||||
|
||||
func (p *headerParser) parseAtomText(dot bool) (string, error) {
|
||||
i := 0
|
||||
for {
|
||||
r, size := utf8.DecodeRuneInString(p.s[i:])
|
||||
if size == 1 && r == utf8.RuneError {
|
||||
return "", fmt.Errorf("mail: invalid UTF-8 in atom-text: %q", p.s)
|
||||
} else if size == 0 || !isAtext(r, dot) {
|
||||
break
|
||||
}
|
||||
i += size
|
||||
}
|
||||
if i == 0 {
|
||||
return "", errors.New("mail: invalid string")
|
||||
}
|
||||
|
||||
var atom string
|
||||
atom, p.s = p.s[:i], p.s[i:]
|
||||
return atom, nil
|
||||
}
|
||||
|
||||
func isAtext(r rune, dot bool) bool {
|
||||
switch r {
|
||||
case '.':
|
||||
return dot
|
||||
// RFC 5322 3.2.3 specials
|
||||
case '(', ')', '[', ']', ';', '@', '\\', ',':
|
||||
return false
|
||||
case '<', '>', '"', ':':
|
||||
return false
|
||||
}
|
||||
return isVchar(r)
|
||||
}
|
||||
|
||||
// isVchar reports whether r is an RFC 5322 VCHAR character.
|
||||
func isVchar(r rune) bool {
|
||||
// Visible (printing) characters
|
||||
return '!' <= r && r <= '~' || isMultibyte(r)
|
||||
}
|
||||
|
||||
// isMultibyte reports whether r is a multi-byte UTF-8 character
|
||||
// as supported by RFC 6532
|
||||
func isMultibyte(r rune) bool {
|
||||
return r >= utf8.RuneSelf
|
||||
}
|
||||
|
||||
func (p *headerParser) parseNoFoldLiteral() (string, error) {
|
||||
if !p.consume('[') {
|
||||
return "", errors.New("mail: missing '[' in no-fold-literal")
|
||||
}
|
||||
|
||||
i := 0
|
||||
for {
|
||||
r, size := utf8.DecodeRuneInString(p.s[i:])
|
||||
if size == 1 && r == utf8.RuneError {
|
||||
return "", fmt.Errorf("mail: invalid UTF-8 in no-fold-literal: %q", p.s)
|
||||
} else if size == 0 || !isDtext(r) {
|
||||
break
|
||||
}
|
||||
i += size
|
||||
}
|
||||
var lit string
|
||||
lit, p.s = p.s[:i], p.s[i:]
|
||||
|
||||
if !p.consume(']') {
|
||||
return "", errors.New("mail: missing ']' in no-fold-literal")
|
||||
}
|
||||
return "[" + lit + "]", nil
|
||||
}
|
||||
|
||||
func isDtext(r rune) bool {
|
||||
switch r {
|
||||
case '[', ']', '\\':
|
||||
return false
|
||||
}
|
||||
return isVchar(r)
|
||||
}
|
||||
|
||||
func (p *headerParser) parseMsgID() (string, error) {
|
||||
if !p.skipCFWS() {
|
||||
return "", errors.New("mail: malformed parenthetical comment")
|
||||
}
|
||||
|
||||
if !p.consume('<') {
|
||||
return "", errors.New("mail: missing '<' in msg-id")
|
||||
}
|
||||
|
||||
left, err := p.parseAtomText(true)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if !p.consume('@') {
|
||||
return "", errors.New("mail: missing '@' in msg-id")
|
||||
}
|
||||
|
||||
var right string
|
||||
if !p.empty() && p.peek() == '[' {
|
||||
// no-fold-literal
|
||||
right, err = p.parseNoFoldLiteral()
|
||||
} else {
|
||||
right, err = p.parseAtomText(true)
|
||||
}
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if !p.consume('>') {
|
||||
return "", errors.New("mail: missing '>' in msg-id")
|
||||
}
|
||||
|
||||
if !p.skipCFWS() {
|
||||
return "", errors.New("mail: malformed parenthetical comment")
|
||||
}
|
||||
|
||||
return left + "@" + right, nil
|
||||
}
|
||||
|
||||
// A Header is a mail header.
|
||||
type Header struct {
|
||||
message.Header
|
||||
}
|
||||
|
||||
// HeaderFromMap creates a header from a map of header fields.
|
||||
//
|
||||
// This function is provided for interoperability with the standard library.
|
||||
// If possible, ReadHeader should be used instead to avoid loosing information.
|
||||
// The map representation looses the ordering of the fields, the capitalization
|
||||
// of the header keys, and the whitespace of the original header.
|
||||
func HeaderFromMap(m map[string][]string) Header {
|
||||
return Header{message.HeaderFromMap(m)}
|
||||
}
|
||||
|
||||
// AddressList parses the named header field as a list of addresses. If the
|
||||
// header field is missing, it returns nil.
|
||||
//
|
||||
// This can be used on From, Sender, Reply-To, To, Cc and Bcc header fields.
|
||||
func (h *Header) AddressList(key string) ([]*Address, error) {
|
||||
v := h.Get(key)
|
||||
if v == "" {
|
||||
return nil, nil
|
||||
}
|
||||
return ParseAddressList(v)
|
||||
}
|
||||
|
||||
// SetAddressList formats the named header field to the provided list of
|
||||
// addresses.
|
||||
//
|
||||
// This can be used on From, Sender, Reply-To, To, Cc and Bcc header fields.
|
||||
func (h *Header) SetAddressList(key string, addrs []*Address) {
|
||||
if len(addrs) > 0 {
|
||||
h.Set(key, formatAddressList(addrs))
|
||||
} else {
|
||||
h.Del(key)
|
||||
}
|
||||
}
|
||||
|
||||
// Date parses the Date header field. If the header field is missing, it
|
||||
// returns the zero time.
|
||||
func (h *Header) Date() (time.Time, error) {
|
||||
v := h.Get("Date")
|
||||
if v == "" {
|
||||
return time.Time{}, nil
|
||||
}
|
||||
return mail.ParseDate(v)
|
||||
}
|
||||
|
||||
// SetDate formats the Date header field.
|
||||
func (h *Header) SetDate(t time.Time) {
|
||||
if !t.IsZero() {
|
||||
h.Set("Date", t.Format(dateLayout))
|
||||
} else {
|
||||
h.Del("Date")
|
||||
}
|
||||
}
|
||||
|
||||
// Subject parses the Subject header field. If there is an error, the raw field
|
||||
// value is returned alongside the error.
|
||||
func (h *Header) Subject() (string, error) {
|
||||
return h.Text("Subject")
|
||||
}
|
||||
|
||||
// SetSubject formats the Subject header field.
|
||||
func (h *Header) SetSubject(s string) {
|
||||
h.SetText("Subject", s)
|
||||
}
|
||||
|
||||
// MessageID parses the Message-ID field. It returns the message identifier,
|
||||
// without the angle brackets. If the message doesn't have a Message-ID header
|
||||
// field, it returns an empty string.
|
||||
func (h *Header) MessageID() (string, error) {
|
||||
v := h.Get("Message-Id")
|
||||
if v == "" {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
p := headerParser{v}
|
||||
return p.parseMsgID()
|
||||
}
|
||||
|
||||
// MsgIDList parses a list of message identifiers. It returns message
|
||||
// identifiers without angle brackets. If the header field is missing, it
|
||||
// returns nil.
|
||||
//
|
||||
// This can be used on In-Reply-To and References header fields.
|
||||
func (h *Header) MsgIDList(key string) ([]string, error) {
|
||||
v := h.Get(key)
|
||||
if v == "" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
p := headerParser{v}
|
||||
var l []string
|
||||
for !p.empty() {
|
||||
msgID, err := p.parseMsgID()
|
||||
if err != nil {
|
||||
return l, err
|
||||
}
|
||||
l = append(l, msgID)
|
||||
}
|
||||
|
||||
return l, nil
|
||||
}
|
||||
|
||||
// GenerateMessageID wraps GenerateMessageIDWithHostname and therefore uses the
|
||||
// hostname of the local machine. This is done to not break existing software.
|
||||
// Wherever possible better use GenerateMessageIDWithHostname, because the local
|
||||
// hostname of a machine tends to not be unique nor a FQDN which especially
|
||||
// brings problems with spam filters.
|
||||
func (h *Header) GenerateMessageID() error {
|
||||
var err error
|
||||
hostname, err := os.Hostname()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return h.GenerateMessageIDWithHostname(hostname)
|
||||
}
|
||||
|
||||
// GenerateMessageIDWithHostname generates an RFC 2822-compliant Message-Id
|
||||
// based on the informational draft "Recommendations for generating Message
|
||||
// IDs", it takes an hostname as argument, so that software using this library
|
||||
// could use a hostname they know to be unique
|
||||
func (h *Header) GenerateMessageIDWithHostname(hostname string) error {
|
||||
now := uint64(time.Now().UnixNano())
|
||||
|
||||
nonceByte := make([]byte, 8)
|
||||
if _, err := rand.Read(nonceByte); err != nil {
|
||||
return err
|
||||
}
|
||||
nonce := binary.BigEndian.Uint64(nonceByte)
|
||||
|
||||
msgID := fmt.Sprintf("%s.%s@%s", base36(now), base36(nonce), hostname)
|
||||
h.SetMessageID(msgID)
|
||||
return nil
|
||||
}
|
||||
|
||||
func base36(input uint64) string {
|
||||
return strings.ToUpper(strconv.FormatUint(input, 36))
|
||||
}
|
||||
|
||||
// SetMessageID sets the Message-ID field. id is the message identifier,
|
||||
// without the angle brackets.
|
||||
func (h *Header) SetMessageID(id string) {
|
||||
if id != "" {
|
||||
h.Set("Message-Id", "<"+id+">")
|
||||
} else {
|
||||
h.Del("Message-Id")
|
||||
}
|
||||
}
|
||||
|
||||
// SetMsgIDList formats a list of message identifiers. Message identifiers
|
||||
// don't include angle brackets.
|
||||
//
|
||||
// This can be used on In-Reply-To and References header fields.
|
||||
func (h *Header) SetMsgIDList(key string, l []string) {
|
||||
if len(l) > 0 {
|
||||
h.Set(key, "<"+strings.Join(l, "> <")+">")
|
||||
} else {
|
||||
h.Del(key)
|
||||
}
|
||||
}
|
||||
|
||||
// Copy creates a stand-alone copy of the header.
|
||||
func (h *Header) Copy() Header {
|
||||
return Header{h.Header.Copy()}
|
||||
}
|
||||
10
vendor/github.com/emersion/go-message/mail/inline.go
generated
vendored
Normal file
10
vendor/github.com/emersion/go-message/mail/inline.go
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
package mail
|
||||
|
||||
import (
|
||||
"github.com/emersion/go-message"
|
||||
)
|
||||
|
||||
// A InlineHeader represents a message text header.
|
||||
type InlineHeader struct {
|
||||
message.Header
|
||||
}
|
||||
9
vendor/github.com/emersion/go-message/mail/mail.go
generated
vendored
Normal file
9
vendor/github.com/emersion/go-message/mail/mail.go
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
// Package mail implements reading and writing mail messages.
|
||||
//
|
||||
// This package assumes that a mail message contains one or more text parts and
|
||||
// zero or more attachment parts. Each text part represents a different version
|
||||
// of the message content (e.g. a different type, a different language and so
|
||||
// on).
|
||||
//
|
||||
// RFC 5322 defines the Internet Message Format.
|
||||
package mail
|
||||
130
vendor/github.com/emersion/go-message/mail/reader.go
generated
vendored
Normal file
130
vendor/github.com/emersion/go-message/mail/reader.go
generated
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
package mail
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/emersion/go-message"
|
||||
)
|
||||
|
||||
// A PartHeader is a mail part header. It contains convenience functions to get
|
||||
// and set header fields.
|
||||
type PartHeader interface {
|
||||
// Add adds the key, value pair to the header.
|
||||
Add(key, value string)
|
||||
// Del deletes the values associated with key.
|
||||
Del(key string)
|
||||
// Get gets the first value associated with the given key. If there are no
|
||||
// values associated with the key, Get returns "".
|
||||
Get(key string) string
|
||||
// Set sets the header entries associated with key to the single element
|
||||
// value. It replaces any existing values associated with key.
|
||||
Set(key, value string)
|
||||
}
|
||||
|
||||
// A Part is either a mail text or an attachment. Header is either a InlineHeader
|
||||
// or an AttachmentHeader.
|
||||
type Part struct {
|
||||
Header PartHeader
|
||||
Body io.Reader
|
||||
}
|
||||
|
||||
// A Reader reads a mail message.
|
||||
type Reader struct {
|
||||
Header Header
|
||||
|
||||
e *message.Entity
|
||||
readers *list.List
|
||||
}
|
||||
|
||||
// NewReader creates a new mail reader.
|
||||
func NewReader(e *message.Entity) *Reader {
|
||||
mr := e.MultipartReader()
|
||||
if mr == nil {
|
||||
// Artificially create a multipart entity
|
||||
// With this header, no error will be returned by message.NewMultipart
|
||||
var h message.Header
|
||||
h.Set("Content-Type", "multipart/mixed")
|
||||
me, _ := message.NewMultipart(h, []*message.Entity{e})
|
||||
mr = me.MultipartReader()
|
||||
}
|
||||
|
||||
l := list.New()
|
||||
l.PushBack(mr)
|
||||
|
||||
return &Reader{Header{e.Header}, e, l}
|
||||
}
|
||||
|
||||
// CreateReader reads a mail header from r and returns a new mail reader.
|
||||
//
|
||||
// If the message uses an unknown transfer encoding or charset, CreateReader
|
||||
// returns an error that verifies message.IsUnknownCharset, but also returns a
|
||||
// Reader that can be used.
|
||||
func CreateReader(r io.Reader) (*Reader, error) {
|
||||
e, err := message.Read(r)
|
||||
if err != nil && !message.IsUnknownCharset(err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewReader(e), err
|
||||
}
|
||||
|
||||
// NextPart returns the next mail part. If there is no more part, io.EOF is
|
||||
// returned as error.
|
||||
//
|
||||
// The returned Part.Body must be read completely before the next call to
|
||||
// NextPart, otherwise it will be discarded.
|
||||
//
|
||||
// If the part uses an unknown transfer encoding or charset, NextPart returns an
|
||||
// error that verifies message.IsUnknownCharset, but also returns a Part that
|
||||
// can be used.
|
||||
func (r *Reader) NextPart() (*Part, error) {
|
||||
for r.readers.Len() > 0 {
|
||||
e := r.readers.Back()
|
||||
mr := e.Value.(message.MultipartReader)
|
||||
|
||||
p, err := mr.NextPart()
|
||||
if err == io.EOF {
|
||||
// This whole multipart entity has been read, continue with the next one
|
||||
r.readers.Remove(e)
|
||||
continue
|
||||
} else if err != nil && !message.IsUnknownCharset(err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if pmr := p.MultipartReader(); pmr != nil {
|
||||
// This is a multipart part, read it
|
||||
r.readers.PushBack(pmr)
|
||||
} else {
|
||||
// This is a non-multipart part, return a mail part
|
||||
mp := &Part{Body: p.Body}
|
||||
t, _, _ := p.Header.ContentType()
|
||||
disp, _, _ := p.Header.ContentDisposition()
|
||||
if disp == "inline" || (disp != "attachment" && strings.HasPrefix(t, "text/")) {
|
||||
mp.Header = &InlineHeader{p.Header}
|
||||
} else {
|
||||
mp.Header = &AttachmentHeader{p.Header}
|
||||
}
|
||||
return mp, err
|
||||
}
|
||||
}
|
||||
|
||||
return nil, io.EOF
|
||||
}
|
||||
|
||||
// Close finishes the reader.
|
||||
func (r *Reader) Close() error {
|
||||
for r.readers.Len() > 0 {
|
||||
e := r.readers.Back()
|
||||
mr := e.Value.(message.MultipartReader)
|
||||
|
||||
if err := mr.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r.readers.Remove(e)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
132
vendor/github.com/emersion/go-message/mail/writer.go
generated
vendored
Normal file
132
vendor/github.com/emersion/go-message/mail/writer.go
generated
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
package mail
|
||||
|
||||
import (
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/emersion/go-message"
|
||||
)
|
||||
|
||||
func initInlineContentTransferEncoding(h *message.Header) {
|
||||
if !h.Has("Content-Transfer-Encoding") {
|
||||
t, _, _ := h.ContentType()
|
||||
if strings.HasPrefix(t, "text/") {
|
||||
h.Set("Content-Transfer-Encoding", "quoted-printable")
|
||||
} else {
|
||||
h.Set("Content-Transfer-Encoding", "base64")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func initInlineHeader(h *InlineHeader) {
|
||||
h.Set("Content-Disposition", "inline")
|
||||
initInlineContentTransferEncoding(&h.Header)
|
||||
}
|
||||
|
||||
func initAttachmentHeader(h *AttachmentHeader) {
|
||||
disp, _, _ := h.ContentDisposition()
|
||||
if disp != "attachment" {
|
||||
h.Set("Content-Disposition", "attachment")
|
||||
}
|
||||
if !h.Has("Content-Transfer-Encoding") {
|
||||
h.Set("Content-Transfer-Encoding", "base64")
|
||||
}
|
||||
}
|
||||
|
||||
// A Writer writes a mail message. A mail message contains one or more text
|
||||
// parts and zero or more attachments.
|
||||
type Writer struct {
|
||||
mw *message.Writer
|
||||
}
|
||||
|
||||
// CreateWriter writes a mail header to w and creates a new Writer.
|
||||
func CreateWriter(w io.Writer, header Header) (*Writer, error) {
|
||||
header = header.Copy() // don't modify the caller's view
|
||||
header.Set("Content-Type", "multipart/mixed")
|
||||
|
||||
mw, err := message.CreateWriter(w, header.Header)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Writer{mw}, nil
|
||||
}
|
||||
|
||||
// CreateInlineWriter writes a mail header to w. The mail will contain an
|
||||
// inline part, allowing to represent the same text in different formats.
|
||||
// Attachments cannot be included.
|
||||
func CreateInlineWriter(w io.Writer, header Header) (*InlineWriter, error) {
|
||||
header = header.Copy() // don't modify the caller's view
|
||||
header.Set("Content-Type", "multipart/alternative")
|
||||
|
||||
mw, err := message.CreateWriter(w, header.Header)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &InlineWriter{mw}, nil
|
||||
}
|
||||
|
||||
// CreateSingleInlineWriter writes a mail header to w. The mail will contain a
|
||||
// single inline part. The body of the part should be written to the returned
|
||||
// io.WriteCloser. Only one single inline part should be written, use
|
||||
// CreateWriter if you want multiple parts.
|
||||
func CreateSingleInlineWriter(w io.Writer, header Header) (io.WriteCloser, error) {
|
||||
header = header.Copy() // don't modify the caller's view
|
||||
initInlineContentTransferEncoding(&header.Header)
|
||||
return message.CreateWriter(w, header.Header)
|
||||
}
|
||||
|
||||
// CreateInline creates a InlineWriter. One or more parts representing the same
|
||||
// text in different formats can be written to a InlineWriter.
|
||||
func (w *Writer) CreateInline() (*InlineWriter, error) {
|
||||
var h message.Header
|
||||
h.Set("Content-Type", "multipart/alternative")
|
||||
|
||||
mw, err := w.mw.CreatePart(h)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &InlineWriter{mw}, nil
|
||||
}
|
||||
|
||||
// CreateSingleInline creates a new single text part with the provided header.
|
||||
// The body of the part should be written to the returned io.WriteCloser. Only
|
||||
// one single text part should be written, use CreateInline if you want multiple
|
||||
// text parts.
|
||||
func (w *Writer) CreateSingleInline(h InlineHeader) (io.WriteCloser, error) {
|
||||
h = InlineHeader{h.Header.Copy()} // don't modify the caller's view
|
||||
initInlineHeader(&h)
|
||||
return w.mw.CreatePart(h.Header)
|
||||
}
|
||||
|
||||
// CreateAttachment creates a new attachment with the provided header. The body
|
||||
// of the part should be written to the returned io.WriteCloser.
|
||||
func (w *Writer) CreateAttachment(h AttachmentHeader) (io.WriteCloser, error) {
|
||||
h = AttachmentHeader{h.Header.Copy()} // don't modify the caller's view
|
||||
initAttachmentHeader(&h)
|
||||
return w.mw.CreatePart(h.Header)
|
||||
}
|
||||
|
||||
// Close finishes the Writer.
|
||||
func (w *Writer) Close() error {
|
||||
return w.mw.Close()
|
||||
}
|
||||
|
||||
// InlineWriter writes a mail message's text.
|
||||
type InlineWriter struct {
|
||||
mw *message.Writer
|
||||
}
|
||||
|
||||
// CreatePart creates a new text part with the provided header. The body of the
|
||||
// part should be written to the returned io.WriteCloser.
|
||||
func (w *InlineWriter) CreatePart(h InlineHeader) (io.WriteCloser, error) {
|
||||
h = InlineHeader{h.Header.Copy()} // don't modify the caller's view
|
||||
initInlineHeader(&h)
|
||||
return w.mw.CreatePart(h.Header)
|
||||
}
|
||||
|
||||
// Close finishes the InlineWriter.
|
||||
func (w *InlineWriter) Close() error {
|
||||
return w.mw.Close()
|
||||
}
|
||||
Reference in New Issue
Block a user