mirror of https://github.com/gophish/gophish
Migrating to use github.com/gomail/gomail to provide:
Better auth compatibility (support for upcoming) embedded images Much faster email sending (sending multiple emails per connection)pull/284/head
parent
1933eb7ff1
commit
a8aac75f99
182
worker/worker.go
182
worker/worker.go
|
@ -6,15 +6,16 @@ import (
|
|||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"log"
|
||||
"net/mail"
|
||||
"net/smtp"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/gophish/gophish/models"
|
||||
"github.com/jordan-wright/email"
|
||||
"gopkg.in/gomail.v2"
|
||||
)
|
||||
|
||||
// Logger is the logger for the worker
|
||||
|
@ -47,27 +48,59 @@ func processCampaign(c *models.Campaign) {
|
|||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
e := email.Email{
|
||||
Subject: c.Template.Subject,
|
||||
From: c.SMTP.FromAddress,
|
||||
}
|
||||
var auth smtp.Auth
|
||||
if c.SMTP.Username != "" && c.SMTP.Password != "" {
|
||||
auth = smtp.PlainAuth("", c.SMTP.Username, c.SMTP.Password, strings.Split(c.SMTP.Host, ":")[0])
|
||||
}
|
||||
tc := &tls.Config{
|
||||
ServerName: c.SMTP.Host,
|
||||
InsecureSkipVerify: c.SMTP.IgnoreCertErrors,
|
||||
}
|
||||
f, err := mail.ParseAddress(c.SMTP.FromAddress)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
ft := f.Name
|
||||
if ft == "" {
|
||||
ft = f.Address
|
||||
fn := f.Name
|
||||
if fn == "" {
|
||||
fn = f.Address
|
||||
}
|
||||
// Setup the message and dial
|
||||
hp := strings.Split(c.SMTP.Host, ":")
|
||||
if len(hp) < 2 {
|
||||
hp = append(hp, "25")
|
||||
}
|
||||
// Any issues should have been caught in validation, so we just log
|
||||
port, err := strconv.Atoi(hp[1])
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
d := gomail.NewDialer(hp[0], port, c.SMTP.Username, c.SMTP.Password)
|
||||
d.TLSConfig = &tls.Config{
|
||||
ServerName: c.SMTP.Host,
|
||||
InsecureSkipVerify: c.SMTP.IgnoreCertErrors,
|
||||
}
|
||||
s, err := d.Dial()
|
||||
// Short circuit if we have an err
|
||||
// However, we still need to update each target
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
for _, t := range c.Results {
|
||||
es := struct {
|
||||
Error string `json:"error"`
|
||||
}{
|
||||
Error: err.Error(),
|
||||
}
|
||||
ej, err := json.Marshal(es)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
err = t.UpdateStatus(models.ERROR)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
err = c.AddEvent(models.Event{Email: t.Email, Message: models.EVENT_SENDING_ERROR, Details: string(ej)})
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
// Send each email
|
||||
e := gomail.NewMessage()
|
||||
for _, t := range c.Results {
|
||||
e.SetHeader("From", c.SMTP.FromAddress)
|
||||
td := struct {
|
||||
models.Result
|
||||
URL string
|
||||
|
@ -79,21 +112,23 @@ func processCampaign(c *models.Campaign) {
|
|||
c.URL + "?rid=" + t.RId,
|
||||
c.URL + "/track?rid=" + t.RId,
|
||||
"<img style='display: none' src='" + c.URL + "/track?rid=" + t.RId + "'/>",
|
||||
ft,
|
||||
fn,
|
||||
}
|
||||
// Parse the templates
|
||||
var subjBuff bytes.Buffer
|
||||
var htmlBuff bytes.Buffer
|
||||
var textBuff bytes.Buffer
|
||||
tmpl, err := template.New("html_template").Parse(c.Template.HTML)
|
||||
tmpl, err := template.New("text_template").Parse(c.Template.Subject)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
err = tmpl.Execute(&htmlBuff, td)
|
||||
err = tmpl.Execute(&subjBuff, td)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
e.HTML = htmlBuff.Bytes()
|
||||
e.SetHeader("Subject", subjBuff.String())
|
||||
Logger.Println("Creating email using template")
|
||||
e.SetHeader("To", t.Email)
|
||||
tmpl, err = template.New("text_template").Parse(c.Template.Text)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
|
@ -102,29 +137,28 @@ func processCampaign(c *models.Campaign) {
|
|||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
e.Text = textBuff.Bytes()
|
||||
tmpl, err = template.New("text_template").Parse(c.Template.Subject)
|
||||
e.SetBody("text/plain", textBuff.String())
|
||||
tmpl, err = template.New("html_template").Parse(c.Template.HTML)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
err = tmpl.Execute(&subjBuff, td)
|
||||
err = tmpl.Execute(&htmlBuff, td)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
e.Subject = string(subjBuff.Bytes())
|
||||
Logger.Println("Creating email using template")
|
||||
e.To = []string{t.Email}
|
||||
e.Attachments = []*email.Attachment{}
|
||||
e.AddAlternative("text/html", htmlBuff.String())
|
||||
// Attach the files
|
||||
for _, a := range c.Template.Attachments {
|
||||
e.Attach(func(a models.Attachment) (string, gomail.FileSetting) {
|
||||
return a.Name, gomail.SetCopyFunc(func(w io.Writer) error {
|
||||
decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(a.Content))
|
||||
_, err = e.Attach(decoder, a.Name, a.Type)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
_, err = io.Copy(w, decoder)
|
||||
return err
|
||||
})
|
||||
}(a))
|
||||
}
|
||||
Logger.Printf("Sending Email to %s\n", t.Email)
|
||||
err = e.SendWithTLS(c.SMTP.Host, auth, tc)
|
||||
err = gomail.Send(s, e)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
es := struct {
|
||||
|
@ -154,6 +188,7 @@ func processCampaign(c *models.Campaign) {
|
|||
Logger.Println(err)
|
||||
}
|
||||
}
|
||||
e.Reset()
|
||||
}
|
||||
err = c.UpdateStatus(models.CAMPAIGN_EMAILS_SENT)
|
||||
if err != nil {
|
||||
|
@ -162,41 +197,42 @@ func processCampaign(c *models.Campaign) {
|
|||
}
|
||||
|
||||
func SendTestEmail(s *models.SendTestEmailRequest) error {
|
||||
e := email.Email{
|
||||
Subject: s.Template.Subject,
|
||||
From: s.SMTP.FromAddress,
|
||||
hp := strings.Split(s.SMTP.Host, ":")
|
||||
if len(hp) < 2 {
|
||||
hp = append(hp, "25")
|
||||
}
|
||||
var auth smtp.Auth
|
||||
if s.SMTP.Username != "" && s.SMTP.Password != "" {
|
||||
auth = smtp.PlainAuth("", s.SMTP.Username, s.SMTP.Password, strings.Split(s.SMTP.Host, ":")[0])
|
||||
}
|
||||
t := &tls.Config{
|
||||
ServerName: s.SMTP.Host,
|
||||
InsecureSkipVerify: s.SMTP.IgnoreCertErrors,
|
||||
}
|
||||
f, err := mail.ParseAddress(s.SMTP.FromAddress)
|
||||
port, err := strconv.Atoi(hp[1])
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
return err
|
||||
}
|
||||
s.From = f.Name
|
||||
if s.From == "" {
|
||||
s.From = f.Address
|
||||
d := gomail.NewDialer(hp[0], port, s.SMTP.Username, s.SMTP.Password)
|
||||
d.TLSConfig = &tls.Config{
|
||||
ServerName: s.SMTP.Host,
|
||||
InsecureSkipVerify: s.SMTP.IgnoreCertErrors,
|
||||
}
|
||||
dc, err := d.Dial()
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
return err
|
||||
}
|
||||
e := gomail.NewMessage()
|
||||
e.SetHeader("From", s.SMTP.FromAddress)
|
||||
e.SetHeader("To", s.Email)
|
||||
Logger.Println("Creating email using template")
|
||||
// Parse the templates
|
||||
var subjBuff bytes.Buffer
|
||||
var htmlBuff bytes.Buffer
|
||||
tmpl, err := template.New("text_template").Parse(s.Template.Subject)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
err = tmpl.Execute(&subjBuff, s)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
e.SetHeader("Subject", subjBuff.String())
|
||||
if s.Template.Text != "" {
|
||||
var textBuff bytes.Buffer
|
||||
tmpl, err := template.New("html_template").Parse(s.Template.HTML)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
err = tmpl.Execute(&htmlBuff, s)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
e.HTML = htmlBuff.Bytes()
|
||||
tmpl, err = template.New("text_template").Parse(s.Template.Text)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
|
@ -205,27 +241,37 @@ func SendTestEmail(s *models.SendTestEmailRequest) error {
|
|||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
e.Text = textBuff.Bytes()
|
||||
tmpl, err = template.New("text_template").Parse(s.Template.Subject)
|
||||
e.SetBody("text/plain", textBuff.String())
|
||||
}
|
||||
if s.Template.HTML != "" {
|
||||
var htmlBuff bytes.Buffer
|
||||
tmpl, err = template.New("html_template").Parse(s.Template.HTML)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
err = tmpl.Execute(&subjBuff, s)
|
||||
err = tmpl.Execute(&htmlBuff, s)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
e.Subject = string(subjBuff.Bytes())
|
||||
e.To = []string{s.Email}
|
||||
// If we don't have a text part, make the html the root part
|
||||
if s.Template.Text == "" {
|
||||
e.SetBody("text/html", htmlBuff.String())
|
||||
} else {
|
||||
e.AddAlternative("text/html", htmlBuff.String())
|
||||
}
|
||||
}
|
||||
// Attach the files
|
||||
for _, a := range s.Template.Attachments {
|
||||
e.Attach(func(a models.Attachment) (string, gomail.FileSetting) {
|
||||
return a.Name, gomail.SetCopyFunc(func(w io.Writer) error {
|
||||
decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(a.Content))
|
||||
_, err = e.Attach(decoder, a.Name, a.Type)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
}
|
||||
_, err = io.Copy(w, decoder)
|
||||
return err
|
||||
})
|
||||
}(a))
|
||||
}
|
||||
Logger.Printf("Sending Email to %s\n", s.Email)
|
||||
err = e.SendWithTLS(s.SMTP.Host, auth, t)
|
||||
err = gomail.Send(dc, e)
|
||||
if err != nil {
|
||||
Logger.Println(err)
|
||||
// For now, let's split the error and return
|
||||
|
|
Loading…
Reference in New Issue