mirror of
https://github.com/wiggin77/mailrelay.git
synced 2024-11-25 08:33:09 +01:00
124 lines
2.7 KiB
Go
124 lines
2.7 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/tls"
|
|
"fmt"
|
|
"io"
|
|
"net/smtp"
|
|
"net/textproto"
|
|
|
|
"github.com/flashmob/go-guerrilla/mail"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
type closeable interface {
|
|
Close() error
|
|
}
|
|
|
|
// sendMail sends the contents of the envelope to a SMTP server.
|
|
func sendMail(e *mail.Envelope, config *relayConfig) error {
|
|
server := fmt.Sprintf("%s:%d", config.SMTPServer, config.SMTPPort)
|
|
to := getTo(e)
|
|
|
|
var msg bytes.Buffer
|
|
msg.Write(e.Data.Bytes())
|
|
msg.WriteString("\r\n")
|
|
|
|
fmt.Println("==== Starting email send ====")
|
|
defer fmt.Println("==== Finished email send ====")
|
|
var err error
|
|
var conn *tls.Conn
|
|
var client *smtp.Client
|
|
var writer io.WriteCloser
|
|
|
|
tlsconfig := &tls.Config{
|
|
InsecureSkipVerify: true,
|
|
ServerName: config.SMTPServer,
|
|
}
|
|
|
|
if conn, err = tls.Dial("tcp", server, tlsconfig); err != nil {
|
|
return errors.Wrap(err, "dial error")
|
|
}
|
|
|
|
if client, err = smtp.NewClient(conn, config.SMTPServer); err != nil {
|
|
close(conn, "conn")
|
|
return errors.Wrap(err, "newclient error")
|
|
}
|
|
shouldCloseClient := true
|
|
defer func(shouldClose *bool) {
|
|
if *shouldClose {
|
|
close(client, "client")
|
|
}
|
|
}(&shouldCloseClient)
|
|
|
|
auth := smtp.PlainAuth("", config.SMTPUsername, config.SMTPPassword, config.SMTPServer)
|
|
if err = client.Auth(auth); err != nil {
|
|
return errors.Wrap(err, "auth error")
|
|
}
|
|
|
|
if err = client.Mail(e.MailFrom.String()); err != nil {
|
|
return errors.Wrap(err, "mail error")
|
|
}
|
|
|
|
for _, addy := range to {
|
|
if err = client.Rcpt(addy); err != nil {
|
|
return errors.Wrap(err, "rcpt error")
|
|
}
|
|
}
|
|
|
|
if writer, err = client.Data(); err != nil {
|
|
return errors.Wrap(err, "data error")
|
|
}
|
|
_, err = writer.Write(msg.Bytes())
|
|
close(writer, "writer")
|
|
if err != nil {
|
|
return errors.Wrap(err, "write error")
|
|
}
|
|
|
|
if err = client.Quit(); isQuitError(err) {
|
|
return errors.Wrap(err, "quit error")
|
|
}
|
|
// We only need to close client if some other error prevented us
|
|
// from getting to `client.Quit`
|
|
shouldCloseClient = false
|
|
return nil
|
|
}
|
|
|
|
func close(c closeable, what string) {
|
|
err := c.Close()
|
|
if err != nil {
|
|
fmt.Printf("!!!!! Error closing %s: %v\n", what, err)
|
|
}
|
|
}
|
|
|
|
func isQuitError(err error) bool {
|
|
if err == nil {
|
|
return false
|
|
}
|
|
e, ok := err.(*textproto.Error)
|
|
if ok {
|
|
// SMTP codes 221 or 250 are acceptable here
|
|
if e.Code == 221 || e.Code == 250 {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
// getTo returns the array of email addresses in the envelope.
|
|
func getTo(e *mail.Envelope) []string {
|
|
var ret []string
|
|
for _, addy := range e.RcptTo {
|
|
ret = append(ret, addy.String())
|
|
}
|
|
return ret
|
|
}
|
|
|
|
func display(b []byte) {
|
|
s := string(b)
|
|
fmt.Println("################################")
|
|
fmt.Printf("%s\n", s)
|
|
fmt.Println("################################")
|
|
}
|