-
-
Save douglasmakey/90753ecf37ac10c25873825097f46300 to your computer and use it in GitHub Desktop.
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)) | |
} |
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.
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.
Hi, @douglasmakey ! I'm getting the same error as the author above. This code results only empty .csv files... :(
H @douglasmakey , Is there any way to include an image in the email body using the GOalng net/smtp
package?
io/ioutils
has deprecated after go 1.16
package main
import (
"bytes"
"encoding/base64"
"fmt"
"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 := os.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))
}
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