mirror of
https://github.com/ncarlier/webhookd.git
synced 2025-04-07 19:29:19 +00:00
feat(notif): add TLS and password support to the SMTP notifier
This commit is contained in:
parent
f5f48381af
commit
c5ca22b15f
|
@ -263,7 +263,10 @@ Options (using query parameters):
|
||||||
|
|
||||||
- `prefix`: Prefix to filter output log
|
- `prefix`: Prefix to filter output log
|
||||||
- `smtp`: SMTP host to use (by default: `localhost:25`)
|
- `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
|
### Authentication
|
||||||
|
|
||||||
|
|
|
@ -1,73 +1,124 @@
|
||||||
package notification
|
package notification
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"net"
|
||||||
"net/smtp"
|
"net/smtp"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/ncarlier/webhookd/pkg/logger"
|
"github.com/ncarlier/webhookd/pkg/logger"
|
||||||
"github.com/ncarlier/webhookd/pkg/model"
|
"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 {
|
type SMTPNotifier struct {
|
||||||
Host string
|
Host string
|
||||||
|
Username string
|
||||||
|
Password string
|
||||||
|
Conn string
|
||||||
From string
|
From string
|
||||||
To string
|
To string
|
||||||
PrefixFilter string
|
PrefixFilter string
|
||||||
}
|
}
|
||||||
|
|
||||||
func newSMTPNotifier(uri *url.URL) *SMTPNotifier {
|
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{
|
return &SMTPNotifier{
|
||||||
Host: getValueOrAlt(uri.Query(), "smtp", "localhost:25"),
|
Host: getValueOrAlt(q, "smtp", "localhost:25"),
|
||||||
From: getValueOrAlt(uri.Query(), "from", "noreply@nunux.org"),
|
Username: getValueOrAlt(q, "username", ""),
|
||||||
|
Password: getValueOrAlt(q, "password", ""),
|
||||||
|
Conn: getValueOrAlt(q, "conn", "plain"),
|
||||||
|
From: getValueOrAlt(q, "from", "noreply@nunux.org"),
|
||||||
To: uri.Opaque,
|
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) buildEmailPayload(work *model.WorkRequest) string {
|
||||||
func (n *SMTPNotifier) Notify(work *model.WorkRequest) error {
|
|
||||||
// Get email body
|
// Get email body
|
||||||
payload := work.GetLogContent(n.PrefixFilter)
|
body := work.GetLogContent(n.PrefixFilter)
|
||||||
if strings.TrimSpace(payload) == "" {
|
if strings.TrimSpace(body) == "" {
|
||||||
// Nothing to notify, abort
|
return ""
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
// Get email subject
|
||||||
// Buidl subject
|
|
||||||
var subject string
|
var subject string
|
||||||
if work.Status == model.Success {
|
if work.Status == model.Success {
|
||||||
subject = fmt.Sprintf("Webhook %s#%d SUCCESS.", work.Name, work.ID)
|
subject = fmt.Sprintf("Webhook %s#%d SUCCESS.", work.Name, work.ID)
|
||||||
} else {
|
} else {
|
||||||
subject = fmt.Sprintf("Webhook %s#%d FAILED.", work.Name, work.ID)
|
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.
|
// Build email payload
|
||||||
c, err := smtp.Dial(n.Host)
|
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 {
|
if err != nil {
|
||||||
return err
|
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
|
// Set the sender and recipient first
|
||||||
if err := c.Mail(n.From); err != nil {
|
if err := client.Mail(n.From); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := c.Rcpt(n.To); err != nil {
|
if err := client.Rcpt(n.To); err != nil {
|
||||||
log.Println(err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send the email body.
|
// Send the email body.
|
||||||
wc, err := c.Data()
|
wc, err := client.Data()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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 {
|
if err != nil {
|
||||||
return err
|
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)
|
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.
|
// 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()))
|
work.MessageChan <- []byte(fmt.Sprintf("error: %s", err.Error()))
|
||||||
}
|
}
|
||||||
// Send notification
|
// Send notification
|
||||||
notification.Notify(&work)
|
go notification.Notify(&work)
|
||||||
|
|
||||||
close(work.MessageChan)
|
close(work.MessageChan)
|
||||||
case <-w.QuitChan:
|
case <-w.QuitChan:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user