Skip to content

Commit

Permalink
Add ssl mailer functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
irnes committed Apr 17, 2017
1 parent 06752d9 commit dbe68f4
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 12 deletions.
33 changes: 31 additions & 2 deletions mail.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
package mailer

import ()
import (
"bufio"
"bytes"
"encoding/base64"
"fmt"
"strings"
)

// Mail struct represents an e-Mail
type Mail struct {
Expand All @@ -25,10 +31,14 @@ type Mail struct {
Body string
}

// NewMail returns a new Mail struct with Headers initialized to an empty map
// NewMail returns a new Mail struct with initialized headers
func NewMail() *Mail {
m := new(Mail)
m.Headers = make(map[string]string)
m.SetHeader("MIME-Version", "1.0")
m.SetHeader("Content-Type", "text/html; charset=\"utf-8\"")
m.SetHeader("Content-Transfer-Encoding", "base64")

return m
}

Expand Down Expand Up @@ -61,3 +71,22 @@ func sliceIt(slice, add []string) []string {
}
return slice
}

// Raw returns a raw message content according to RFC 822-style
func (m *Mail) Raw() []byte {
var message bytes.Buffer
w := bufio.NewWriter(&message)

fmt.Fprintf(w, "From: %s <%s>\r\n", m.FromName, m.From)
fmt.Fprintf(w, "To: %s\r\n", strings.Join(m.To, ","))
for k, v := range m.Headers {
fmt.Fprintf(w, "%s: %s\r\n", k, v)
}

fmt.Fprintf(w, "Subject: %s\r\n\r\n%s\r\n", m.Subject,
base64.StdEncoding.EncodeToString([]byte(m.Body)))

w.Flush()

return message.Bytes()
}
53 changes: 49 additions & 4 deletions mailer.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package mailer

import (
"crypto/tls"
"fmt"
"net/smtp"
)
Expand Down Expand Up @@ -50,13 +51,10 @@ func (m *SMTP) Send(mail *Mail) (err error) {
server := fmt.Sprintf("%s:%d", m.Host, m.Port)
// Set up authentication information.
auth := smtp.PlainAuth("", m.User, m.Pass, m.Host)
// Prepare message content according to RFC 822-style
msg := []byte(fmt.Sprintf("From: %s <%s>\r\nSubject: %s\r\n\r\n%s\r\n",
mail.FromName, mail.From, mail.Subject, mail.Body))

// Connect to the server, authenticate, set the sender and recipient,
// and send the email all in one step.
err = smtp.SendMail(server, auth, mail.From, mail.To, msg)
err = smtp.SendMail(server, auth, mail.From, mail.To, mail.Raw())

return
}
Expand All @@ -69,5 +67,52 @@ type SMTPSLL struct {

// Send an email and waits for the process to end, giving proper error feedback
func (m *SMTPSLL) Send(mail *Mail) (err error) {
// TLS config
tlsconfig := &tls.Config{
InsecureSkipVerify: true,
ServerName: m.Host,
}

// Call tls.Dial instead of smtp.Dial for smtp servers running on 465
// that require an ssl connection from the very beginning (no starttls)
server := fmt.Sprintf("%s:%d", m.Host, m.Port)
conn, err := tls.Dial("tcp", server, tlsconfig)
if err != nil {
return
}
defer conn.Close()

c, err := smtp.NewClient(conn, m.Host)
if err != nil {
return
}
defer c.Quit()

// Set up authentication information.
auth := smtp.PlainAuth("", m.User, m.Pass, m.Host)
if err = c.Auth(auth); err != nil {
return
}

// Set sender and recipents
if err = c.Mail(mail.From); err != nil {
return
}
for _, rcpt := range mail.To {
c.Rcpt(rcpt)
}

// Data
w, err := c.Data()
if err != nil {
return
}
defer w.Close()

_, err = w.Write(mail.Raw())
if err != nil {
return
}

return nil
}
22 changes: 16 additions & 6 deletions mailer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,19 @@ import (

// Provide a valid smtp config
var (
host = "mail.xxx.com"
user = "[email protected]"
pass = "xxx"
recipent = "[email protected]"
host = "mail.xxx.com"
user = "[email protected]"
pass = "xxx"
recipent = "[email protected]"
recipent2 = "[email protected]"
)

func TestSMTP(t *testing.T) {
mail := NewMail()
mail.FromName = "Go Mailer"
mail.From = user
mail.Subject = "Go SMTP Test"
mail.Body = "This is a test mail from Go Mailer via SMTP"
mail.Body = "This is a test e-mail from Go Mailer via SMTP"
mail.SetTo(recipent)

mailer := NewMailer(host, 25, user, pass, false)
Expand All @@ -31,8 +32,17 @@ func TestSMTPSSL(t *testing.T) {
mail.FromName = "Go Mailer"
mail.From = user
mail.Subject = "Go SMTP SSL Test"
mail.Body = "This is a test from Go Mailer via SMTP SSL"
// the rich message body
mail.Body = `
<h2>Hello from Go Mailer</h2>
<p>
This is a test e-mail from Go Mailer via SMTP SSL
</p>
`

// multiple recipents
mail.SetTo(recipent)
mail.SetTo(recipent2)

mailer := NewMailer(host, 465, user, pass, true)
if err := mailer.Send(mail); err != nil {
Expand Down

0 comments on commit dbe68f4

Please sign in to comment.