package main | |
import ( | |
"bytes" | |
"encoding/base64" | |
"fmt" | |
"io/ioutil" | |
"mime/multipart" | |
"net/smtp" | |
"os" | |
"path/filepath" | |
) | |
var ( | |
host = os.Getenv("EMAIL_HOST") | |
username = os.Getenv("EMAiL_USERNAME") | |
password = os.Getenv("EMAIL_PASSWORD") | |
portNumber = os.Getenv("EMAIL_PORT") | |
) | |
type Sender struct { | |
auth smtp.Auth | |
} | |
type Message struct { | |
To []string | |
CC []string | |
BCC []string | |
Subject string | |
Body string | |
Attachments map[string][]byte | |
} | |
func New() *Sender { | |
auth := smtp.PlainAuth("", username, password, host) | |
return &Sender{auth} | |
} | |
func (s *Sender) Send(m *Message) error { | |
return smtp.SendMail(fmt.Sprintf("%s:%s", host, portNumber), s.auth, username, m.To, m.ToBytes()) | |
} | |
func NewMessage(s, b string) *Message { | |
return &Message{Subject: s, Body: b, Attachments: make(map[string][]byte)} | |
} | |
func (m *Message) AttachFile(src string) error { | |
b, err := ioutil.ReadFile(src) | |
if err != nil { | |
return err | |
} | |
_, fileName := filepath.Split(src) | |
m.Attachments[fileName] = b | |
return nil | |
} | |
func (m *Message) ToBytes() []byte { | |
buf := bytes.NewBuffer(nil) | |
withAttachments := len(m.Attachments) > 0 | |
buf.WriteString(fmt.Sprintf("Subject: %s\n", m.Subject)) | |
buf.WriteString(fmt.Sprintf("To: %s\n", strings.Join(m.To, ","))) | |
if len(m.CC) > 0 { | |
buf.WriteString(fmt.Sprintf("Cc: %s\n", strings.Join(m.CC, ","))) | |
} | |
if len(m.BCC) > 0 { | |
buf.WriteString(fmt.Sprintf("Bcc: %s\n", strings.Join(m.BCC, ","))) | |
} | |
buf.WriteString("MIME-Version: 1.0\n") | |
writer := multipart.NewWriter(buf) | |
boundary := writer.Boundary() | |
if withAttachments { | |
buf.WriteString(fmt.Sprintf("Content-Type: multipart/mixed; boundary=%s\n", boundary)) | |
buf.WriteString(fmt.Sprintf("--%s\n", boundary)) | |
} else { | |
buf.WriteString("Content-Type: text/plain; charset=utf-8\n") | |
} | |
buf.WriteString(m.Body) | |
if withAttachments { | |
for k, v := range m.Attachments { | |
buf.WriteString(fmt.Sprintf("\n\n--%s\n", boundary)) | |
buf.WriteString(fmt.Sprintf("Content-Type: %s\n", http.DetectContentType(v))) | |
buf.WriteString("Content-Transfer-Encoding: base64\n") | |
buf.WriteString(fmt.Sprintf("Content-Disposition: attachment; filename=%s\n", k)) | |
b := make([]byte, base64.StdEncoding.EncodedLen(len(v))) | |
base64.StdEncoding.Encode(b, v) | |
buf.Write(b) | |
buf.WriteString(fmt.Sprintf("\n--%s", boundary)) | |
} | |
buf.WriteString("--") | |
} | |
return buf.Bytes() | |
} | |
func main() { | |
sender := New() | |
m := NewMessage("Test", "Body message.") | |
m.To = []string{"to@gmail.com"} | |
m.CC = []string{"copy1@gmail.com", "copy2@gmail.com"} | |
m.BCC = []string{"bc@gmail.com"} | |
m.AttachFile("/path/to/file") | |
fmt.Println(sender.Send(m)) | |
} |
I tried with with O365 email as:
var (
host = "smtp.office365.com" // os.Getenv("EMAIL_HOST")
username = "xxxx" // os.Getenv("EMAiL_USERNAME")
password = "xxxx" // os.Getenv("EMAIL_PASSWORD")
portNumber = 587 // os.Getenv("EMAIL_PORT")
)
But got the below error:
dial tcp: lookup tcp/%!s(int=587): getaddrinfow: The specified class was not found.
The I fixed the port to be:
portNumber = "587"
but I got:
504 5.7.4 Unrecognized authentication type [GV0P278CA0003.CHEP278.PROD.OUTLOOK.COM]
Any thought?
How to add array of bcc,cc to buf?
How about simply adding headers for Bcc and Cc just like Subject like below.
buf.WriteString(fmt.Sprintf("Cc: %s\n", m.Ccied)) //Cc
buf.WriteString(fmt.Sprintf("Bcc: %s\n", m.Bccied)) //Bcc
Hi ,
With adding a CSV file as an attachment , it seems we need to change the MIME type?
As i am getting the empty csv file with the email sent with above code
even with below change getting empty csv file as an attachment
buf.WriteString(fmt.Sprintf("\n\n--%s\n", boundary))
>>buf.WriteString("Content-Type: text/csv\n")
buf.WriteString("Content-Transfer-Encoding: base64\n")
buf.WriteString(fmt.Sprintf("Content-Disposition: attachment; filename=%s\n", k))
Hi @AddyM I made a small change that should help you with that, I tested it and it worked, also you can contact me directly, I will gladly give you a hand.
i tried this with mailtrap as :
but i got this
https://github.com/stvoidit/gosmtp
Please try my version based on the example of this code. Due to the specific situation, I have to use my own implementation, because popular solutions for some reason do not work, although I have implemented very basic things and perhaps not in the best way, but it works for me.
Thanks for your code. A few days spent looking for a good solution, there were problems with sending files and my mail service (yandex.ru). slightly redesigned your code for yourself, in the standard version does not work on SSL.
You can see my fork if you interesting. Thx