kit/emailclient/emailclient.go

200 lines
4.6 KiB
Go
Raw Normal View History

2023-10-10 12:31:53 +00:00
package emailclient
import (
"crypto/tls"
"errors"
"fmt"
"net"
"net/mail"
"net/smtp"
log "github.com/sirupsen/logrus"
)
// SMTPCredentials is a struc holding the information needed to connect to a SMTP server
type SMTPCredentials struct {
Host string
Email string
Password string
}
// emailClient is a struct holding the information requiered to send with SMTP
type emailClient struct {
client *smtp.Client
}
// EmailClient is the generic interface for all client sending emails
type EmailClient interface {
SendMsg(headers map[string]string, body string)
}
// NewSMTPClient (host, user, password) returns a SMTPClient
//
// host is the SMTP server used to connect
// port is the SMTP port used to connect
// user is usually the email address use to connect to SMTP
// password is the associated password
func NewSMTPClient(host string, port string, user string, password string) (EmailClient, error) {
var ec emailClient
log.Infof("user: (%s) pass: (%s)", user, password)
auth := smtp.PlainAuth("", user, password, host)
// TLS config
tlsconfig := &tls.Config{
InsecureSkipVerify: false,
ServerName: host,
}
// Here is the key, you need to call tls.Dial instead of smtp.Dial
// for smtp servers running on 465 that require an ssl connection
// from the very beginning (no starttls)
var conn *tls.Conn
var c *smtp.Client
var err error
if port == "465" {
conn, err = tls.Dial("tcp", host+":"+port, tlsconfig)
if err != nil {
log.Error("[sendMail] ERROR while dialing: " + err.Error())
return ec, err
}
c, err = smtp.NewClient(conn, host)
if err != nil {
log.Error("[sendMail] ERROR while NewClient: " + err.Error())
return ec, err
}
} else {
c, err = smtp.Dial(host + ":" + port)
if err != nil {
log.Error("[sendMail] ERROR while Dialing: " + err.Error())
return ec, err
}
err = c.StartTLS(tlsconfig)
if err != nil {
log.Error("[sendMail] ERROR while StartTLS: " + err.Error())
return ec, err
}
}
// defer c.Quit()
// defer c.Close()
ec.client = c
// Auth
if err = ec.client.Auth(auth); err != nil {
log.Error("[sendMail] ERROR while Auth: " + err.Error())
return ec, err
}
return ec, nil
}
// NewGmailClient returns a GmailClient
func NewGmailClient(email, pass string) (EmailClient, error) {
var ec emailClient
// cred.Host = "smtp.gmail.com:587"
echost := "smtp.gmail.com:465"
if pass == "" {
log.Error("Email password missing")
return ec, errors.New("Email password missing")
}
host, _, _ := net.SplitHostPort(echost)
auth := smtp.PlainAuth("", email, pass, host)
// TLS config
tlsconfig := &tls.Config{
InsecureSkipVerify: true,
ServerName: host,
}
// Cavehat, you need to call tls.Dial instead of smtp.Dial
// for smtp servers running on 465 that require an ssl connection
// from the very beginning (no starttls)
conn, err := tls.Dial("tcp", echost, tlsconfig)
if err != nil {
log.Error(fmt.Sprintf("Dial error: " + err.Error()))
return ec, err
}
client, err := smtp.NewClient(conn, host)
if err != nil {
log.Error(fmt.Sprintf("NewClient error: " + err.Error()))
return ec, err
}
ec.client = client
// Auth
if err = ec.client.Auth(auth); err != nil {
log.Error(fmt.Sprintf("Auth error: %s (%s)", err, host))
return ec, err
}
return ec, nil
}
// SendMsg send a message (email) to rcpt which is in the 'headers' parameter ('To' key) and whose content is the 'body' parameter.
// Ohter keys of interest in headers are 'Subject' and 'MIME-version'
func (ec emailClient) SendMsg(headers map[string]string, body string) {
from := mail.Address{Name: "", Address: headers["From"]}
to := mail.Address{Name: "", Address: headers["To"]}
// headers["To"] = to.String()
if _, ok := headers["Subject"]; ok {
headers["Subject"] = "Subject unknown"
}
log.Printf("from = %s", headers["From"])
log.Printf("to = %s", headers["To"])
log.Printf("subj = %s", headers["Subject"])
// Setup message
message := ""
for k, v := range headers {
message += fmt.Sprintf("%s: %s\r\n", k, v)
}
message += "\r\n" + body
c := ec.client
// To && From
if err := c.Mail(from.Address); err != nil {
log.Error("Can't set From: " + err.Error())
return
}
if err := c.Rcpt(to.Address); err != nil {
log.Error("Can't set To: " + err.Error())
return
}
// Data
w, err := c.Data()
if err != nil {
log.Error("Can't set Data: " + err.Error())
return
}
_, err = w.Write([]byte(message))
if err != nil {
log.Error("Can't write Data: " + err.Error())
return
}
err = w.Close()
if err != nil {
log.Error("Can't Close: " + err.Error())
return
}
err = c.Quit()
if err != nil {
log.Error("Can't Quit: " + err.Error())
return
}
c.Close()
}