mirror of
https://github.com/ncarlier/webhookd.git
synced 2025-04-05 18:03:41 +00:00
feat(notif): add TLS and password support to the SMTP notifier
close #39
This commit is contained in:
parent
f5f48381af
commit
f29a1748ef
|
@ -263,7 +263,10 @@ Options (using query parameters):
|
|||
|
||||
- `prefix`: Prefix to filter output log
|
||||
- `smtp`: SMTP host to use (by default: `localhost:25`)
|
||||
- `from`: Sender email (by default: `webhookd <noreply@nunux.org>`)
|
||||
- `username`: SMTP username (not set by default)
|
||||
- `password`: SMTP password (not set by default)
|
||||
- `conn`: SMTP connection type (`tls`, `tls-insecure` or by default: `plain`)
|
||||
- `from`: Sender email (by default: `noreply@nunux.org`)
|
||||
|
||||
### Authentication
|
||||
|
||||
|
|
|
@ -1,73 +1,124 @@
|
|||
package notification
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/smtp"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ncarlier/webhookd/pkg/logger"
|
||||
"github.com/ncarlier/webhookd/pkg/model"
|
||||
)
|
||||
|
||||
// SMTPNotifier is able to send notifcation to a email destination.
|
||||
// SMTPNotifier is able to send notification to a email destination.
|
||||
type SMTPNotifier struct {
|
||||
Host string
|
||||
Username string
|
||||
Password string
|
||||
Conn string
|
||||
From string
|
||||
To string
|
||||
PrefixFilter string
|
||||
}
|
||||
|
||||
func newSMTPNotifier(uri *url.URL) *SMTPNotifier {
|
||||
logger.Info.Println("using SMTP notification system: ", uri.Opaque)
|
||||
logger.Info.Println("using SMTP notification system:", uri.Opaque)
|
||||
q := uri.Query()
|
||||
return &SMTPNotifier{
|
||||
Host: getValueOrAlt(uri.Query(), "smtp", "localhost:25"),
|
||||
From: getValueOrAlt(uri.Query(), "from", "noreply@nunux.org"),
|
||||
Host: getValueOrAlt(q, "smtp", "localhost:25"),
|
||||
Username: getValueOrAlt(q, "username", ""),
|
||||
Password: getValueOrAlt(q, "password", ""),
|
||||
Conn: getValueOrAlt(q, "conn", "plain"),
|
||||
From: getValueOrAlt(q, "from", "noreply@nunux.org"),
|
||||
To: uri.Opaque,
|
||||
PrefixFilter: getValueOrAlt(uri.Query(), "prefix", "notify:"),
|
||||
PrefixFilter: getValueOrAlt(q, "prefix", "notify:"),
|
||||
}
|
||||
}
|
||||
|
||||
// Notify send a notification to a email destination.
|
||||
func (n *SMTPNotifier) Notify(work *model.WorkRequest) error {
|
||||
func (n *SMTPNotifier) buildEmailPayload(work *model.WorkRequest) string {
|
||||
// Get email body
|
||||
payload := work.GetLogContent(n.PrefixFilter)
|
||||
if strings.TrimSpace(payload) == "" {
|
||||
// Nothing to notify, abort
|
||||
return nil
|
||||
body := work.GetLogContent(n.PrefixFilter)
|
||||
if strings.TrimSpace(body) == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Buidl subject
|
||||
// Get email subject
|
||||
var subject string
|
||||
if work.Status == model.Success {
|
||||
subject = fmt.Sprintf("Webhook %s#%d SUCCESS.", work.Name, work.ID)
|
||||
} else {
|
||||
subject = fmt.Sprintf("Webhook %s#%d FAILED.", work.Name, work.ID)
|
||||
}
|
||||
// Build email headers
|
||||
headers := make(map[string]string)
|
||||
headers["From"] = n.From
|
||||
headers["To"] = n.To
|
||||
headers["Subject"] = subject
|
||||
|
||||
// Connect to the remote SMTP server.
|
||||
c, err := smtp.Dial(n.Host)
|
||||
// Build email payload
|
||||
payload := ""
|
||||
for k, v := range headers {
|
||||
payload += fmt.Sprintf("%s: %s\r\n", k, v)
|
||||
}
|
||||
payload += "\r\n" + body
|
||||
return payload
|
||||
}
|
||||
|
||||
// Notify send a notification to a email destination.
|
||||
func (n *SMTPNotifier) Notify(work *model.WorkRequest) error {
|
||||
hostname, _, _ := net.SplitHostPort(n.Host)
|
||||
payload := n.buildEmailPayload(work)
|
||||
if payload == "" {
|
||||
// Nothing to notify, abort
|
||||
return nil
|
||||
}
|
||||
|
||||
// Dial connection
|
||||
conn, err := net.DialTimeout("tcp", n.Host, 5*time.Second)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Connect to SMTP server
|
||||
client, err := smtp.NewClient(conn, hostname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if n.Conn == "tls" || n.Conn == "tls-insecure" {
|
||||
// TLS config
|
||||
tlsConfig := &tls.Config{
|
||||
InsecureSkipVerify: n.Conn == "tls-insecure",
|
||||
ServerName: hostname,
|
||||
}
|
||||
if err := client.StartTLS(tlsConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Set auth if needed
|
||||
if n.Username != "" {
|
||||
if err := client.Auth(smtp.PlainAuth("", n.Username, n.Password, hostname)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Set the sender and recipient first
|
||||
if err := c.Mail(n.From); err != nil {
|
||||
if err := client.Mail(n.From); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.Rcpt(n.To); err != nil {
|
||||
log.Println(err)
|
||||
if err := client.Rcpt(n.To); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Send the email body.
|
||||
wc, err := c.Data()
|
||||
wc, err := client.Data()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = fmt.Fprintf(wc, "Subject: %s\r\n\r\n%s\r\n\r\n", subject, payload)
|
||||
_, err = wc.Write([]byte(payload))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -79,5 +130,5 @@ func (n *SMTPNotifier) Notify(work *model.WorkRequest) error {
|
|||
logger.Info.Printf("job %s#%d notification sent to %s\n", work.Name, work.ID, n.To)
|
||||
|
||||
// Send the QUIT command and close the connection.
|
||||
return c.Quit()
|
||||
return client.Quit()
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ func (w Worker) Start() {
|
|||
work.MessageChan <- []byte(fmt.Sprintf("error: %s", err.Error()))
|
||||
}
|
||||
// Send notification
|
||||
notification.Notify(&work)
|
||||
go notification.Notify(&work)
|
||||
|
||||
close(work.MessageChan)
|
||||
case <-w.QuitChan:
|
||||
|
|
Loading…
Reference in New Issue
Block a user