summary refs log tree commit diff stats
path: root/commands/compose
diff options
context:
space:
mode:
authorDrew DeVault <sir@cmpwn.com>2019-05-14 14:05:29 -0400
committerDrew DeVault <sir@cmpwn.com>2019-05-14 14:07:27 -0400
commit29de3297a157c0ac109121152fe2b5737fc81d95 (patch)
tree875fed0384d689392a7454c7a71fa2017d28d15c /commands/compose
parent6c36e04c1f7f7e222c71c5c8e7e7337744fe9c34 (diff)
downloadaerc-29de3297a157c0ac109121152fe2b5737fc81d95.tar.gz
Implement sending emails /o/
Diffstat (limited to 'commands/compose')
-rw-r--r--commands/compose/send-message.go120
1 files changed, 114 insertions, 6 deletions
diff --git a/commands/compose/send-message.go b/commands/compose/send-message.go
index b9fc9d2..b101e12 100644
--- a/commands/compose/send-message.go
+++ b/commands/compose/send-message.go
@@ -1,8 +1,15 @@
 package compose
 
 import (
+	"crypto/tls"
 	"errors"
-	"os"
+	"fmt"
+	"net/mail"
+	"net/url"
+	"strings"
+
+	"github.com/emersion/go-sasl"
+	"github.com/emersion/go-smtp"
 
 	"git.sr.ht/~sircmpwn/aerc2/widgets"
 )
@@ -16,14 +23,115 @@ func SendMessage(aerc *widgets.Aerc, args []string) error {
 		return errors.New("Usage: send-message")
 	}
 	composer, _ := aerc.SelectedTab().(*widgets.Composer)
-	//config := composer.Config()
-	f, err := os.Create("/tmp/test.eml")
+	config := composer.Config()
+
+	if config.Outgoing == "" {
+		return errors.New(
+			"No outgoing mail transport configured for this account")
+	}
+
+	uri, err := url.Parse(config.Outgoing)
 	if err != nil {
-		panic(err)
+		return err
+	}
+	var (
+		scheme string
+		auth   string = "plain"
+	)
+	parts := strings.Split(uri.Scheme, "+")
+	if len(parts) == 1 {
+		scheme = parts[0]
+	} else if len(parts) == 2 {
+		scheme = parts[0]
+		auth = parts[1]
+	} else {
+		return fmt.Errorf("Unknown transfer protocol %s", uri.Scheme)
+	}
+
+	header, rcpts, err := composer.Header()
+	if err != nil {
+		return err
+	}
+
+	if config.From == "" {
+		return errors.New("No 'From' configured for this account")
+	}
+	from, err := mail.ParseAddress(config.From)
+	if err != nil {
+		return err
+	}
+
+	var (
+		saslClient sasl.Client
+		conn       *smtp.Client
+	)
+	switch auth {
+	case "":
+		fallthrough
+	case "none":
+		saslClient = nil
+	case "plain":
+		password, _ := uri.User.Password()
+		saslClient = sasl.NewPlainClient("", uri.User.Username(), password)
+	default:
+		return fmt.Errorf("Unsupported auth mechanism %s", auth)
+	}
+
+	tlsConfig := &tls.Config{
+		// TODO: ask user first
+		InsecureSkipVerify: true,
+	}
+	switch scheme {
+	case "smtp":
+		host := uri.Host
+		if !strings.ContainsRune(host, ':') {
+			host = host + ":587" // Default to submission port
+		}
+		conn, err = smtp.Dial(host)
+		if err != nil {
+			return err
+		}
+		defer conn.Close()
+		if sup, _ := conn.Extension("STARTTLS"); sup {
+			// TODO: let user configure tls?
+			if err = conn.StartTLS(tlsConfig); err != nil {
+				return err
+			}
+		}
+	case "smtps":
+		host := uri.Host
+		if !strings.ContainsRune(host, ':') {
+			host = host + ":465" // Default to smtps port
+		}
+		conn, err = smtp.DialTLS(host, tlsConfig)
+		if err != nil {
+			return err
+		}
+		defer conn.Close()
+	}
+
+	// TODO: sendmail
+	if saslClient != nil {
+		if err = conn.Auth(saslClient); err != nil {
+			return err
+		}
+	}
+	// TODO: the user could conceivably want to use a different From and sender
+	if err = conn.Mail(from.Address); err != nil {
+		return err
+	}
+	for _, rcpt := range rcpts {
+		if err = conn.Rcpt(rcpt); err != nil {
+			return err
+		}
 	}
-	_, err = composer.Message(f)
+	wc, err := conn.Data()
 	if err != nil {
-		panic(err)
+		return err
 	}
+	defer wc.Close()
+	composer.WriteMessage(header, wc)
+	composer.Close()
+	aerc.RemoveTab(composer)
 	return nil
 }