forked from domodwyer/mailyak
-
Notifications
You must be signed in to change notification settings - Fork 1
/
attachments.go
84 lines (68 loc) · 1.92 KB
/
attachments.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package mailyak
import (
"encoding/base64"
"fmt"
"io"
"net/http"
"net/textproto"
)
// DetectContentType needs at most 512 bytes
const sniffLen = 512
// AttachmentEmailer extends the Emailer interface to provide attachment support
type AttachmentEmailer interface {
Emailer
Attach(name string, data io.Reader)
ClearAttachments()
}
type partCreator interface {
CreatePart(header textproto.MIMEHeader) (io.Writer, error)
}
type writeWrapper interface {
new(w io.Writer) io.Writer
}
type attachment struct {
filename string
content io.Reader
}
// Attach adds an attachment to the email with the given filename.
//
// Note: The attachment data isn't read until Send() is called
func (m *MailYak) Attach(name string, r io.Reader) {
m.attachments = append(m.attachments, attachment{
filename: name,
content: r,
})
}
// ClearAttachments removes all current attachments
func (m *MailYak) ClearAttachments() {
m.attachments = []attachment{}
}
// writeAttachments loops over the attachments, guesses their content-type and
// writes the data as a line-broken base64 string (using the splitter mutator)
func (m *MailYak) writeAttachments(mixed partCreator, splitter writeWrapper) error {
h := make([]byte, sniffLen)
for _, item := range m.attachments {
hLen, err := item.content.Read(h)
if err != nil && err != io.EOF {
return err
}
ctype := fmt.Sprintf("%s;\n\tfilename=%s", http.DetectContentType(h[:hLen]), item.filename)
disp := fmt.Sprintf("attachment;\n\tfilename=%s", item.filename)
part, err := mixed.CreatePart(textproto.MIMEHeader{
"Content-Type": {ctype},
"Content-Disposition": {disp},
"Content-Transfer-Encoding": {"base64"},
})
if err != nil {
return err
}
encoder := base64.NewEncoder(base64.StdEncoding, splitter.new(part))
encoder.Write(h[:hLen])
// More to write?
if hLen == sniffLen {
io.Copy(encoder, item.content)
}
encoder.Close()
}
return nil
}