co89757
6/5/2017 - 6:48 AM

Email sending using Go

Email sending using Go

package main

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/smtp"
	"strings"
)

//Mailer contains info on email sender and receiver
type Mailer struct {
	SenderEmail    string   `json:"senderEmail"`
	Password       string   `json:"password"`
	SMTPServerHost string   `json:"smtpServerHost"`
	SMTPServerPort int      `json:"smtpServerPort"`
	ReceiverEmails []string `json:"receiverEmails"`
}

// NewMailer inits a new mailer based on configuration
func NewMailer(in io.Reader) (mail *Mailer, err error) {
	decoder := json.NewDecoder(in)
	mail = new(Mailer)
	err = decoder.Decode(mail)
	if err != nil {
		log.Println(err)
		return
	}
	return
}

func validateMailConfig(mailer Mailer) error {
	if mailer.SMTPServerHost == "" || mailer.SMTPServerPort == 0 {
		return fmt.Errorf("Error: no SMTP server or port configured")
	}
	if len(mailer.ReceiverEmails) < 1 {
		return fmt.Errorf("Error: No mail receiver is specified")
	}
	if !strings.Contains(mailer.SenderEmail, "@") {
		return fmt.Errorf("Error: invalid email sender: %s", mailer.SenderEmail)
	}
	return nil

}

func composeBody(subject, body, name, from string) []byte {
	buf := bytes.NewBuffer(nil)
	buf.WriteString("Subject: " + subject + "\r\n")
	buf.WriteString("MIME-Version: 1.0\r\n")
	buf.WriteString(fmt.Sprintf("From: %s <%s>\r\n", name, from))
	buf.WriteString(fmt.Sprintf("Content-Type: text/html; charset=utf-8\r\n\r\n"))
	buf.WriteString(body)
	return buf.Bytes()
}

//SendEmail sends the mail with subject and body set
func (mailer Mailer) SendEmail(subject, senderName, body string) (err error) {
	err = validateMailConfig(mailer)
	if err != nil {
		return
	}
	auth := smtp.PlainAuth(
		"",
		mailer.SenderEmail,
		mailer.Password,
		mailer.SMTPServerHost)
	conn, err := smtp.Dial(fmt.Sprintf("%s:%d", mailer.SMTPServerHost, mailer.SMTPServerPort))
	if err != nil {
		return
	}
	err = conn.StartTLS(&tls.Config{ServerName: mailer.SMTPServerHost})
	if err != nil {
		return
	}
	err = conn.Auth(auth)
	if err != nil {
		return
	}
	err = conn.Mail(mailer.SenderEmail)
	if err != nil {
		if strings.Contains(err.Error(), "530 5.5.1") {
			err = fmt.Errorf("Error: Authentication failure. ")

		}
		return
	}
	for _, recv := range mailer.ReceiverEmails {
		err = conn.Rcpt(recv)
		if err != nil {
			return
		}
	}

	wc, err := conn.Data()
	if err != nil {
		return
	}
	defer wc.Close()
	bodybytes := composeBody(subject, body, senderName, mailer.SenderEmail)
	_, err = wc.Write(bodybytes)
	if err != nil {
		return
	}
	return nil
}