158 lines
3.7 KiB
Go
158 lines
3.7 KiB
Go
|
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)
|
||
|
}
|
||
|
}
|