diff options
author | Drew DeVault <sir@cmpwn.com> | 2019-05-14 14:05:29 -0400 |
---|---|---|
committer | Drew DeVault <sir@cmpwn.com> | 2019-05-14 14:07:27 -0400 |
commit | 29de3297a157c0ac109121152fe2b5737fc81d95 (patch) | |
tree | 875fed0384d689392a7454c7a71fa2017d28d15c /commands | |
parent | 6c36e04c1f7f7e222c71c5c8e7e7337744fe9c34 (diff) |
Implement sending emails /o/
Diffstat (limited to 'commands')
-rw-r--r-- | commands/compose/send-message.go | 120 |
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 } |