Skip to content

Instantly share code, notes, and snippets.

@CzBiX
Created July 26, 2020 13:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CzBiX/bd69c9e342e89c75b203b100d0cafa42 to your computer and use it in GitHub Desktop.
Save CzBiX/bd69c9e342e89c75b203b100d0cafa42 to your computer and use it in GitHub Desktop.
The tiny mail command write in golang.
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
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment