email.go 6.7 KiB
Newer Older
package email

import (
	"bytes"
	"crypto/tls"
	"html/template"
	"strings"
	"sync"

	"corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/utiliymdl/guidmdl"

	"gopkg.in/gomail.v2"

	"corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/configmdl"
	"corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/errormdl"
	"corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/loggermdl"
Mayuri Shinde's avatar
Mayuri Shinde committed
	raymond "github.com/aymerick/raymond"
Roshan Patil's avatar
Roshan Patil committed
// EmailConfig - EmailConfig
type EmailConfig struct {
Roshan Patil's avatar
Roshan Patil committed
	HostName  string `json:"hostName"`
	Server    string `json:"server"`
	Port      int    `json:"port"`
	Username  string `json:"username"`
	Password  string `json:"password"`
	SSL       bool   `json:"SSL"`
	IsDefault bool   `json:"isDefault"`
}

var once sync.Once
var config = EmailConfig{}
var emailInitError error

// Init - initializes toml file configurations
func Init(tomlFilepath string) error {
	once.Do(func() {
		_, err := configmdl.InitConfig(tomlFilepath, &config)
		if errormdl.CheckErr(err) != nil {
			loggermdl.LogError(err)
			emailInitError = err
			return
		}
	})
	return emailInitError
}

type Email struct {
	from        string
Vikram Ingawale's avatar
Vikram Ingawale committed
	replyTo     string
	to          []string
	cc          []string
	bcc         []string
	subject     string
	attachments []string
	body        string
	plainBody   string // alternate text if template fails
Vikram Ingawale's avatar
Vikram Ingawale committed
func NewEmail(to, cc, bcc, attachments []string, from, replyTo, subject, body string) *Email {
	return &Email{
		from:        from,
Vikram Ingawale's avatar
Vikram Ingawale committed
		replyTo:     replyTo,
		to:          to,
		cc:          cc,
		bcc:         bcc,
		subject:     subject,
		attachments: attachments,
		body:        body,
	}
}

// SetAlternateText - set alternate text for email
func (email *Email) SetAlternateText(plainBody string) {
	email.plainBody = plainBody
}

// SendMail - send email service sends email as per the given html template and data
Mayuri Shinde's avatar
Mayuri Shinde committed
//templateData can contain any type of values, including array, slice, map, struct and func
func (email *Email) SendMail(templateFilePath string, templateData interface{}) error {
	err := email.ParseTemplateFile(templateFilePath, templateData)
	if errormdl.CheckErr(err) != nil {
		loggermdl.LogError(err)
		return err
	}
	err = email.ParsePlainText(email.plainBody, templateData)
	if errormdl.CheckErr(err) != nil {
		loggermdl.LogError(err)
		return err
	}
	if err := email.Send(); errormdl.CheckErr1(err) != nil {
Mayuri Shinde's avatar
Mayuri Shinde committed
		loggermdl.LogError("error occured while calling SendMail: ", errormdl.CheckErr1(err))
		return errormdl.Wrap("Failed to send the email to: " + strings.Join(email.to, ", "))
	}
	return nil
}

func (email *Email) ParseTemplateFile(templateFilePath string, templateData interface{}) error {
	tmplt, err := template.ParseFiles(templateFilePath)
	if errormdl.CheckErr(err) != nil {
Mayuri Shinde's avatar
Mayuri Shinde committed
		loggermdl.LogError("error occured while calling parseTemplateFile: ", errormdl.CheckErr(err))
		return err
	}
	buffer := new(bytes.Buffer)
	if err = tmplt.Execute(buffer, templateData); errormdl.CheckErr1(err) != nil {
Mayuri Shinde's avatar
Mayuri Shinde committed
		loggermdl.LogError("error occured while calling parseTemplateFile: ", errormdl.CheckErr1(err))
		return err
	}
	email.body = buffer.String()
	return nil
}

Mayuri Shinde's avatar
Mayuri Shinde committed
// SendMailWithHandlebar - send email service sends email as per the given html text and data
//templateData can contain any type of values, including array, slice, map, struct and func
func (email *Email) SendMailWithHandlebar(templateText string, templateData interface{}) error {
	err := email.parseTemplateText(templateText, templateData)
	if errormdl.CheckErr(err) != nil {
		loggermdl.LogError(err)
		return err
	}
	if err := email.Send(); errormdl.CheckErr1(err) != nil {
		loggermdl.LogError("error occured while calling SendMailWithHandlebar: ", errormdl.CheckErr1(err))
		return errormdl.Wrap("Failed to send the email to: " + strings.Join(email.to, ", "))
	}
	return nil
}

func (email *Email) parseTemplateText(templateText string, templateData interface{}) error {
	tmplt, err := raymond.Parse(templateText)
	if errormdl.CheckErr(err) != nil {
		loggermdl.LogError("error occured while calling parseTemplateText: ", errormdl.CheckErr(err))
		return err
	}
	emailbody, err := tmplt.Exec(templateData)
	if errormdl.CheckErr1(err) != nil {
		loggermdl.LogError("error occured while calling parseTemplateText: ", errormdl.CheckErr1(err))
		return err
	}
	email.body = emailbody
	return nil
}

// Send -send email
func (email *Email) Send() error {
	domain, domainErr := getSenderDomain(email.from)
	if domainErr != nil {
		loggermdl.LogError("error getting domain address: ", domainErr)
		return domainErr
	}
	message := gomail.NewMessage()
	message.SetHeader("From", email.from)
	message.SetHeader("To", email.to...)
Akshay Bharambe's avatar
Akshay Bharambe committed
	message.SetHeader("Reply-To", email.replyTo)
	message.SetHeader("Cc", email.cc...)
	message.SetHeader("Bcc", email.bcc...)
	message.SetHeader("Subject", email.subject)
	message.SetHeader("Message-ID", getMSGIDHeader(domain, guidmdl.GetGUID()))
	if len(strings.TrimSpace(email.plainBody)) == 0 {
		message.SetBody("text/html", email.body)
	} else {
		message.SetBody("text/plain", email.plainBody)
		message.AddAlternative("text/html", email.body)
	for _, attachment := range email.attachments {
		message.Attach(attachment) // attach whatever you want
	}
	dialer := gomail.Dialer{Host: config.Server, Port: config.Port, Username: config.Username, Password: config.Password, SSL: config.SSL}
	dialer.TLSConfig = &tls.Config{InsecureSkipVerify: !config.SSL}
	if err := dialer.DialAndSend(message); errormdl.CheckErr1(err) != nil {
Mayuri Shinde's avatar
Mayuri Shinde committed
		loggermdl.LogError("error occured while calling Send(): ", errormdl.CheckErr1(err))
func getMSGIDHeader(domain, guid string) string {
	return "<" + guid + "@" + domain + ">"
}

func getSenderDomain(from string) (string, error) {
	s := strings.Split(from, "@")
	if len(s) != 2 {
		return "", errormdl.Wrap("invalid email id for sender")
	}

	return s[1], nil
}

// SendMailSMTP - send email service sends email as per the given html template and data using smtp
// func (email *Email) SendMailSMTP(templateFilePath string, templateData interface{}) error {
// 	err := email.parseTemplate(templateFilePath, templateData)
// 	if err != nil {
// 		loggermdl.LogError(err)
// 		return err
// 	}
// 	if err := email.sendMailSMTP(); err != nil {
// 		loggermdl.LogError(err)
// 		return errormdl.Wrap("Failed to send the email to: " + strings.Join(email.to, ", "))
// 	}
// 	return nil
// }
// func (email *Email) sendMailSMTP() error {
// 	body := "To: " + strings.Join(email.to, ",") + "\r\nSubject: " + email.subject + "\r\n" + constantmdl.MIME + "\r\n" + email.body
// 	SMTP := fmt.Sprintf("%s:%d", config.Server, config.Port)
// 	if err := smtp.SendMail(SMTP, smtp.PlainAuth("", config.Email, config.Password, config.Server), config.Email, email.to, []byte(body)); err != nil {
// 		return err
// 	}
// 	return nil
// }