package main import ( "crypto/tls" "flag" "fmt" "io/ioutil" "net" "net/smtp" "os" "os/user" "strings" ) const sslPort = 465 func main() { subject := flag.String("subject", "", "subject") flag.Parse() address := flag.Arg(0) if address == "" { panic("Invalid email address") } msg := getMessage(*subject) err := sendMail(address, msg) if err != nil { panic(err) } } func sendMail(to string, msg []byte) error { mailname := getMailname() from := fmt.Sprintf("%s@%s", getUsername(), mailname) server, conn := getServerConn(to) c, err := smtp.NewClient(conn, server) if err != nil { return err } defer c.Close() if err = c.Hello(mailname); err != nil { return err } if err = c.Mail(from); err != nil { return err } if err = c.Rcpt(to); err != nil { return err } w, err := c.Data() if err != nil { return err } _, err = w.Write(msg) if err != nil { return err } err = w.Close() if err != nil { return err } return c.Quit() } func getUsername() string { user, err := user.Current() if err != nil { panic(err) } return user.Username } func getMailname() string { data, err := ioutil.ReadFile("/etc/mailname") if err != nil { hostname, err := os.Hostname() if err != nil { panic(err) } return hostname } content := string(data) return strings.TrimSpace(strings.SplitN(content, "\n", 1)[0]) } func getServerConn(address string) (string, *tls.Conn) { server := strings.Split(address, "@")[1] mxs, err := net.LookupMX(server) if err != nil { panic(err) } host := mxs[0].Host tlsConfig := &tls.Config{ ServerName: server, } conn, err := tls.Dial("tcp", fmt.Sprintf("%s:%d", host, sslPort), tlsConfig) if err != nil { panic(err) } return server, conn } func getMessage(subject string) []byte { buf, err := ioutil.ReadAll(os.Stdin) if err != nil { panic(err) } if subject == "" { return buf } h := fmt.Sprintf("Subject: %s\r\n\r\n", subject) buf = append([]byte(h), buf...) return buf }