woodpecker/plugin/notify/email/email.go

164 lines
4 KiB
Go

package email
import (
"bytes"
"fmt"
"net"
"net/smtp"
"strings"
"github.com/drone/config"
"github.com/drone/drone/shared/model"
)
const (
NotifyAlways = "always" // always send email notification
NotifyNever = "never" // never send email notifications
NotifyAuthor = "author" // only send email notifications to the author
NotifyTrue = "true" // alias for NotifyTrue
NotifyFalse = "false" // alias for NotifyFalse
NotifyOn = "on" // alias for NotifyTrue
NotifyOff = "off" // alias for NotifyFalse
NotifyBlame = "blame" // alias for NotifyAuthor
)
const (
Subject = "[%s] %s/%s (%s - %s)"
)
var (
DefaultHost = config.String("smtp-host", "")
DefaultPort = config.String("smtp-port", "")
DefaultFrom = config.String("smtp-from", "")
DefaultUser = config.String("smtp-user", "")
DefaultPass = config.String("smtp-pass", "")
)
type Email struct {
Recipients []string `yaml:"recipients"`
Success string `yaml:"on_success"`
Failure string `yaml:"on_failure"`
Host string `yaml:"host"`
Port string `yaml:"port"`
From string `yaml:"from"`
Username string `yaml:"username"`
Password string `yaml:"password"`
}
// Send will send an email, either success or failure,
// based on the Commit Status.
func (e *Email) Send(context *model.Request) error {
var status = context.Commit.Status
switch status {
// no builds are triggered for pending builds
case model.StatusEnqueue, model.StatusStarted:
return nil
case model.StatusSuccess:
return e.sendSuccess(context)
default:
return e.sendFailure(context)
}
}
// sendFailure sends email notifications to the list of
// recipients indicating the build failed.
func (e *Email) sendFailure(context *model.Request) error {
switch e.Failure {
case NotifyFalse, NotifyNever, NotifyOff:
return nil
// if configured to email the author, replace
// the recipiends with the commit author email.
case NotifyBlame, NotifyAuthor:
e.Recipients = []string{context.Commit.Author}
}
// generate the email failure template
var buf bytes.Buffer
err := failureTemplate.ExecuteTemplate(&buf, "_", context)
if err != nil {
return err
}
// generate the email subject
var subject = fmt.Sprintf(
Subject,
context.Commit.Status,
context.Repo.Owner,
context.Repo.Name,
context.Commit.Branch,
context.Commit.ShaShort(),
)
return e.send(subject, buf.String(), e.Recipients)
}
// sendSuccess sends email notifications to the list of
// recipients indicating the build was a success.
func (e *Email) sendSuccess(context *model.Request) error {
switch e.Success {
case NotifyFalse, NotifyNever, NotifyOff:
return nil
// if configured to email the author, replace
// the recipiends with the commit author email.
case NotifyBlame, NotifyAuthor:
e.Recipients = []string{context.Commit.Author}
}
// generate the email success template
var buf bytes.Buffer
err := successTemplate.ExecuteTemplate(&buf, "_", context)
if err != nil {
return err
}
// generate the email subject
var subject = fmt.Sprintf(
Subject,
context.Commit.Status,
context.Repo.Owner,
context.Repo.Name,
context.Commit.Branch,
context.Commit.ShaShort(),
)
return e.send(subject, buf.String(), e.Recipients)
}
func (e *Email) send(subject, body string, recipients []string) error {
if len(recipients) == 0 {
return nil
}
// the user can provide their own smtp server
// configuration. If None provided, attempt to
// use the global configuration set in the environet
// variables.
if len(*DefaultHost) != 0 {
e.Host = *DefaultHost
e.Port = *DefaultPort
e.From = *DefaultFrom
e.Username = *DefaultUser
e.Password = *DefaultPass
}
var auth smtp.Auth
var addr = net.JoinHostPort(e.Host, e.Port)
// setup the authentication to the smtp server
// if the username and password are provided.
if len(e.Username) > 0 {
auth = smtp.PlainAuth("", e.Username, e.Password, e.Host)
}
// genereate the raw email message
var to = strings.Join(e.Recipients, ",")
var raw = fmt.Sprintf(rawMessage, e.From, to, subject, body)
return smtp.SendMail(addr, auth, e.From, e.Recipients, []byte(raw))
}