diff --git a/DOCS.md b/DOCS.md index 5be51c4..06e9af0 100644 --- a/DOCS.md +++ b/DOCS.md @@ -22,3 +22,59 @@ notify: recipients: - octocat@github.com ``` + +### Custom Templates + +In some cases you may want to customize the look and feel of the email message +so you can use custom templates. For the use case we expose the following +additional parameters, all of the accept a custom handlebars template, directly +provided as a string or as a remote URL which gets fetched and parsed: + +* `subject` - A handlebars template to create a custom subject. For more + details take a look at the [docs](http://handlebarsjs.com/). You can see the + default template [here](https://github.com/drone-plugins/drone-email/blob/master/template.go#L4) +* `template` - A handlebars template to create a custom template. For more + details take a look at the [docs](http://handlebarsjs.com/). You can see the + default template [here](https://github.com/drone-plugins/drone-email/blob/master/template.go#L8-L292) + +Example configuration that generate a custom email: + +```yaml +notify: + email: + from: noreply@github.com + host: smtp.mailgun.org + username: octocat + password: 12345 + recipients: + - octocat@github.com + subject: > + [{{ build.status }}] + {{ repo.owner }}/{{ repo.name }} + ({{ build.branch }} - {{ truncate build.commit 8 }}) + template: > + https://git.io/vgvPz +``` + +### Skip SSL verify + +In some cases you may want to skip SSL verification, even if we discourage that +as it leads to an unsecure environment. Please use this option only within your +intranet and/or with truested resources. For this use case we expose the +following additional parameter: + +* `skip_verify` - Skip verification of SSL certificates + +Example configuration that skips SSL verification: + +```yaml +notify: + email: + from: noreply@github.com + host: smtp.mailgun.org + username: octocat + password: 12345 + skip_verify: true + recipients: + - octocat@github.com +``` diff --git a/README.md b/README.md index 8b2c889..7db2d28 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ make deps build "finished_at": 1421029813, "message": "Update the Readme", "author": "johnsmith", - "author_email": "john.smith@gmail.com" + "author_email": "john.smith@gmail.com", "event": "push", "branch": "master", "commit": "436b7a6e2abaddfd35740527353e78a227ddcb2c", diff --git a/main.go b/main.go index 367f523..e63cfb1 100644 --- a/main.go +++ b/main.go @@ -32,6 +32,14 @@ func main() { } } + if vargs.Subject == "" { + vargs.Subject = defaultSubject + } + + if vargs.Template == "" { + vargs.Template = defaultTemplate + } + if vargs.Port == 0 { vargs.Port = 587 } @@ -45,8 +53,6 @@ func main() { if err != nil { fmt.Println(err) - os.Exit(1) - return } } diff --git a/sender.go b/sender.go index e90adeb..49e85cd 100644 --- a/sender.go +++ b/sender.go @@ -1,116 +1,113 @@ package main import ( - "bytes" - "fmt" - "net" - "net/smtp" - "strconv" - "strings" + "crypto/tls" "github.com/drone/drone-go/drone" -) - -const ( - Subject = "[%s] %s/%s (%s - %s)" + "github.com/drone/drone-go/template" + "github.com/go-gomail/gomail" + "github.com/jaytaylor/html2text" ) func Send(context *Context) error { - switch context.Build.Status { - case drone.StatusSuccess: - return SendSuccess(context) - default: - return SendFailure(context) + payload := &drone.Payload{ + System: &context.System, + Repo: &context.Repo, + Build: &context.Build, } -} -// SendFailure sends email notifications to the list of -// recipients indicating the build failed. -func SendFailure(context *Context) error { - // generate the email failure template - var buf bytes.Buffer - err := failureTemplate.ExecuteTemplate(&buf, "_", context) + subject, plain, html, err := build( + payload, + context, + ) if err != nil { return err } - // generate the email subject - var subject = fmt.Sprintf( - Subject, - context.Build.Status, - context.Repo.Owner, - context.Repo.Name, - context.Build.Branch, - context.Build.Commit[:8], + return send( + subject, + plain, + html, + context, ) - - return send(subject, buf.String(), context) } -// SendSuccess sends email notifications to the list of -// recipients indicating the build was a success. -func SendSuccess(context *Context) error { - // generate the email success template - var buf bytes.Buffer - err := successTemplate.ExecuteTemplate(&buf, "_", context) +func build(payload *drone.Payload, context *Context) (string, string, string, error) { + subject, err := template.RenderTrim( + context.Vargs.Subject, + payload) if err != nil { - return err + return "", "", "", err } - // generate the email subject - var subject = fmt.Sprintf( - Subject, - context.Build.Status, - context.Repo.Owner, - context.Repo.Name, - context.Build.Branch, - context.Build.Commit[:8], + html, err := template.RenderTrim( + context.Vargs.Template, + payload, ) - return send(subject, buf.String(), context) + if err != nil { + return "", "", "", err + } + + plain, err := html2text.FromString( + html, + ) + + if err != nil { + return "", "", "", err + } + + return subject, plain, html, nil } -func send(subject, body string, c *Context) error { +func send(subject, plainBody, htmlBody string, c *Context) error { if len(c.Vargs.Recipients) == 0 { c.Vargs.Recipients = []string{ c.Build.Email, } } - var auth smtp.Auth + m := gomail.NewMessage() - var addr = net.JoinHostPort( + m.SetHeader( + "To", + c.Vargs.Recipients..., + ) + + m.SetHeader( + "From", + c.Vargs.From, + ) + + m.SetHeader( + "Subject", + subject, + ) + + m.AddAlternative( + "text/plain", + plainBody, + ) + + m.AddAlternative( + "text/html", + htmlBody, + ) + + d := gomail.NewPlainDialer( c.Vargs.Host, - strconv.Itoa(c.Vargs.Port)) + c.Vargs.Port, + c.Vargs.Username, + c.Vargs.Password, + ) - // setup the authentication to the smtp server - // if the username and password are provided. - if len(c.Vargs.Username) > 0 { - auth = smtp.PlainAuth( - "", - c.Vargs.Username, - c.Vargs.Password, - c.Vargs.Host) + if c.Vargs.SkipVerify { + d.TLSConfig = &tls.Config{ + InsecureSkipVerify: true, + } } - // genereate the raw email message - var to = strings.Join( - c.Vargs.Recipients, - ",") - - var raw = fmt.Sprintf( - rawMessage, - c.Vargs.From, - to, - subject, - body) - - return smtp.SendMail( - addr, - auth, - c.Vargs.From, - c.Vargs.Recipients, - []byte(raw)) + return d.DialAndSend(m) } diff --git a/template.go b/template.go index c492a53..ab8cda5 100644 --- a/template.go +++ b/template.go @@ -1,41 +1,293 @@ package main -import ( - "html/template" -) +var defaultSubject = ` +[{{ build.status }}] {{ repo.owner }}/{{ repo.name }} ({{ build.branch }} - {{ truncate build.commit 8 }}) +` -// raw email message template -var rawMessage = `From: %s -To: %s -Subject: %s -MIME-version: 1.0 -Content-Type: text/html; charset="UTF-8" -%s` +var defaultTemplate = ` + + + + + -// default success email template -var successTemplate = template.Must(template.New("_").Parse(` -

- Build was Successful - (see results) -

-

Repository: {{.Repo.Owner}}/{{.Repo.Name}}

-

Commit: {{.Build.Commit}}

-

Author: {{.Build.Author}}

-

Branch: {{.Build.Branch}}

-

Message:

-

{{ .Build.Message }}

-`)) + + + + + + + + + +
+
+ + + {{#success build.status}} + + {{else}} + + {{/success}} + + + + +
+ + Successful build #{{ build.number }} + + + + Failed build #{{ build.number }} + +
+ + + + + + + + + + + + + + + + + + + + + +
+ Repo: + + {{ repo.owner }}/{{ repo.name }} +
+ Author: + + {{ build.author }} +
+ Branch: + + {{ build.branch }} +
+ Commit: + + {{ truncate build.commit 8 }} +
+ Time: + + {{ duration build.started_at build.finished_at }} +
+
+ + + + +
+ {{ build.message }} +
+
+
+
+ + +` diff --git a/types.go b/types.go index fa39fda..a07ef8a 100644 --- a/types.go +++ b/types.go @@ -11,6 +11,9 @@ type Params struct { From string `json:"from"` Username string `json:"username"` Password string `json:"password"` + Subject string `json:"subject"` + Template string `json:"template"` + SkipVerify bool `json:"skip_verify"` } type Context struct {