aboutsummaryrefslogtreecommitdiff
path: root/smtp.go
diff options
context:
space:
mode:
authorSimon Ser <contact@emersion.fr>2019-12-03 16:27:49 +0100
committerSimon Ser <contact@emersion.fr>2019-12-03 16:27:49 +0100
commit89cebfd8199d172058ff89cd8586ed12866139e0 (patch)
tree680ecca3e65eb824af3477eef4c84dacff3cff60 /smtp.go
parent702719c072dea73ed5ec046fa640b3151ebcbc55 (diff)
downloadalps-89cebfd8199d172058ff89cd8586ed12866139e0.tar.gz
alps-89cebfd8199d172058ff89cd8586ed12866139e0.zip
Add basic SMTP support
Diffstat (limited to 'smtp.go')
-rw-r--r--smtp.go112
1 files changed, 112 insertions, 0 deletions
diff --git a/smtp.go b/smtp.go
new file mode 100644
index 0000000..d4b8ea2
--- /dev/null
+++ b/smtp.go
@@ -0,0 +1,112 @@
+package koushin
+
+import (
+ "fmt"
+ "time"
+ "io"
+
+ "github.com/emersion/go-message/mail"
+ "github.com/emersion/go-smtp"
+)
+
+func (s *Server) connectSMTP() (*smtp.Client, error) {
+ var c *smtp.Client
+ var err error
+ if s.smtp.tls {
+ c, err = smtp.DialTLS(s.smtp.host, nil)
+ if err != nil {
+ return nil, fmt.Errorf("failed to connect to SMTPS server: %v", err)
+ }
+ } else {
+ c, err = smtp.Dial(s.smtp.host)
+ if err != nil {
+ return nil, fmt.Errorf("failed to connect to SMTP server: %v", err)
+ }
+ if !s.smtp.insecure {
+ if err := c.StartTLS(nil); err != nil {
+ c.Close()
+ return nil, fmt.Errorf("STARTTLS failed: %v", err)
+ }
+ }
+ }
+
+ return c, err
+}
+
+type OutgoingMessage struct {
+ from string
+ to []string
+ subject string
+ text string
+}
+
+func (msg *OutgoingMessage) WriteTo(w io.Writer) error {
+ from := []*mail.Address{{"", msg.from}}
+
+ to := make([]*mail.Address, len(msg.to))
+ for i, addr := range msg.to {
+ to[i] = &mail.Address{"", addr}
+ }
+
+ var h mail.Header
+ h.SetDate(time.Now())
+ h.SetAddressList("From", from)
+ h.SetAddressList("To", to)
+ h.SetText("Subject", msg.subject)
+
+ mw, err := mail.CreateWriter(w, h)
+ if err != nil {
+ return fmt.Errorf("failed to create mail writer: %v", err)
+ }
+
+ var th mail.InlineHeader
+ th.Set("Content-Type", "text/plain; charset=utf-8")
+
+ tw, err := mw.CreateSingleInline(th)
+ if err != nil {
+ return fmt.Errorf("failed to create text part: %v", err)
+ }
+ defer tw.Close()
+
+ if _, err := io.WriteString(tw, msg.text); err != nil {
+ return fmt.Errorf("failed to write text part: %v", err)
+ }
+
+ if err := tw.Close(); err != nil {
+ return fmt.Errorf("failed to close text part: %v", err)
+ }
+
+ if err := mw.Close(); err != nil {
+ return fmt.Errorf("failed to close mail writer: %v", err)
+ }
+
+ return nil
+}
+
+func sendMessage(c *smtp.Client, msg *OutgoingMessage) error {
+ if err := c.Mail(msg.from, nil); err != nil {
+ return fmt.Errorf("MAIL FROM failed: %v", err)
+ }
+
+ for _, to := range msg.to {
+ if err := c.Rcpt(to); err != nil {
+ return fmt.Errorf("RCPT TO failed: %v", err)
+ }
+ }
+
+ w, err := c.Data()
+ if err != nil {
+ return fmt.Errorf("DATA failed: %v", err)
+ }
+ defer w.Close()
+
+ if err := msg.WriteTo(w); err != nil {
+ return fmt.Errorf("failed to write outgoing message: %v", err)
+ }
+
+ if err := w.Close(); err != nil {
+ return fmt.Errorf("failed to close SMTP data writer: %v", err)
+ }
+
+ return nil
+}