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 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
|
package mail
import (
"encoding/base64"
"errors"
"io/ioutil"
"mime"
"path/filepath"
)
// File represents the file that can be added to the email message.
// You can add attachment from file in path, from base64 string or from []byte.
// You can define if attachment is inline or not.
// Only one, Data, B64Data or FilePath is supported. If multiple are set, then
// the first in that order is used.
type File struct {
// FilePath is the path of the file to attach.
FilePath string
// Name is the name of file in attachment. Required for Data and B64Data. Optional for FilePath.
Name string
// MimeType of attachment. If empty then is obtained from Name (if not empty) or FilePath. If cannot obtained, application/octet-stream is set.
MimeType string
// B64Data is the base64 string to attach.
B64Data string
// Data is the []byte of file to attach.
Data []byte
// Inline defines if attachment is inline or not.
Inline bool
}
type attachType int
const (
attachData attachType = iota
attachB64
attachFile
)
// Attach allows you to add an attachment to the email message.
// The attachment can be inlined
func (email *Email) Attach(file *File) *Email {
if email.Error != nil {
return email
}
var name = file.Name
var mimeType = file.MimeType
// if no alternative name was provided, get the filename
if len(name) == 0 && len(file.FilePath) > 0 {
_, name = filepath.Split(file.FilePath)
}
// get the mimetype
if mimeType == "" {
mimeType = mime.TypeByExtension(filepath.Ext(name))
if mimeType == "" {
mimeType = "application/octet-stream"
}
}
attachTy, err := getAttachmentType(file)
if err != nil {
email.Error = errors.New("Mail Error: Failed to add attachment with following error: " + err.Error())
return email
}
file.Name = name
file.MimeType = mimeType
switch attachTy {
case attachData:
email.attachData(file)
case attachB64:
email.Error = email.attachB64(file)
case attachFile:
email.Error = email.attachFile(file)
}
return email
}
func getAttachmentType(file *File) (attachType, error) {
// 1- data
// 2- base64
// 3- file
// first check if Data
if len(file.Data) > 0 {
// data requires a name
if len(file.Name) == 0 {
return 0, errors.New("attach from bytes requires a name")
}
return attachData, nil
}
// check if base64
if len(file.B64Data) > 0 {
// B64Data requires a name
if len(file.Name) == 0 {
return 0, errors.New("attach from base64 string requires a name")
}
return attachB64, nil
}
// check if file
if len(file.FilePath) > 0 {
return attachFile, nil
}
return 0, errors.New("empty attachment")
}
// attachB64 does the low level attaching of the files but decoding base64
func (email *Email) attachB64(file *File) error {
// decode the string
dec, err := base64.StdEncoding.DecodeString(file.B64Data)
if err != nil {
return errors.New("Mail Error: Failed to decode base64 attachment with following error: " + err.Error())
}
email.attachData(&File{
Name: file.Name,
MimeType: file.MimeType,
Data: dec,
Inline: file.Inline,
})
return nil
}
func (email *Email) attachFile(file *File) error {
data, err := ioutil.ReadFile(file.FilePath)
if err != nil {
return errors.New("Mail Error: Failed to add file with following error: " + err.Error())
}
email.attachData(&File{
Name: file.Name,
MimeType: file.MimeType,
Data: data,
Inline: file.Inline,
})
return nil
}
// attachData does the low level attaching of the in-memory data
func (email *Email) attachData(file *File) {
// use inlines and attachments because is necessary to know if message has related parts and mixed parts
if file.Inline {
email.inlines = append(email.inlines, file)
} else {
email.attachments = append(email.attachments, file)
}
}
|