All Products
Search
Document Center

Direct Mail:Call SMTP using Go: Sample code

Last Updated:Nov 17, 2025

Use port 80

You can use the Go language to send emails over SMTP. This code is verified on Go version 1.16.5.

Note

To use TLS encryption on port 465, see the section below. Do not use the code for port 80 for this purpose.

package main

import (
    "fmt"
    "net/smtp"
    "strings"
		"time"
)

func SendToMail(user, password, host, subject, date, body, mailtype, replyToAddress string, to, cc, bcc []string) error {
    hp := strings.Split(host, ":")
    auth := smtp.PlainAuth("", user, password, hp[0])
    var content_type string
    if mailtype == "html" {
        content_type = "Content-Type: text/" + mailtype + "; charset=UTF-8"
    } else {
        content_type = "Content-Type: text/plain" + "; charset=UTF-8"
    }

    cc_address := strings.Join(cc, ";")
    bcc_address := strings.Join(bcc, ";")
    to_address := strings.Join(to, ";")
    msg := []byte("To: " + to_address + "\r\nFrom: " + user + "\r\nSubject: " + subject+ "\r\nDate: " + date + "\r\nReply-To: " + replyToAddress + "\r\nCc: " + cc_address + "\r\nBcc: " + bcc_address + "\r\n" + content_type + "\r\n\r\n" + body)
    send_to := MergeSlice(to, cc)
    send_to = MergeSlice(send_to, bcc)
    err := smtp.SendMail(host, auth, user, send_to, msg)
    return err
}

func main() {
    user := "The sender address created in the console"
    password := "The SMTP password set in the console"
    host := "smtpdm.aliyun.com:80"
    to := []string{"recipient_address","recipient_address_1"}
    cc := []string{"cc_address","cc_address_1"}
    bcc := []string{"bcc_address","bcc_address_1"}
    subject := "test Golang to sendmail"
		date := fmt.Sprintf("%s", time.Now().Format(time.RFC1123Z))
    mailtype :="html"
    replyToAddress:="a***@example.net"
    body := "<html><body><h3>Test send to email</h3></body></html>"
    fmt.Println("send email")
    err := SendToMail(user, password, host, subject,date, body, mailtype, replyToAddress, to, cc, bcc)
    if err != nil {
        fmt.Println("Send mail error!")
        fmt.Println(err)
    } else {
        fmt.Println("Send mail success!")
    }
}

func MergeSlice(s1 []string, s2 []string) []string {
    slice := make([]string, len(s1)+len(s2))
    copy(slice, s1)
    copy(slice[len(s1):], s2)
    return slice
}
Note

If you use Go version 1.9.2, an "unencrypted connection" error may occur because this version requires encrypted authentication. To resolve this issue, use LOGIN authentication by adding the following code.

type loginAuth struct {
    username, password string
}

func LoginAuth(username, password string) smtp.Auth {
    return &loginAuth{username, password}
}

func (a *loginAuth) Start(server *smtp.ServerInfo) (string, []byte, error) {
    // return "LOGIN", []byte{}, nil
    return "LOGIN", []byte(a.username), nil
}

func (a *loginAuth) Next(fromServer []byte, more bool) ([]byte, error) {
    if more {
        switch string(fromServer) {
        case "Username:":
            return []byte(a.username), nil
        case "Password:":
            return []byte(a.password), nil
        }
    }
    return nil, nil
}

Modify the call method as follows:

auth := LoginAuth(user, password)

Use port 465

package main

import (
    "crypto/tls"
    "fmt"
    "log"
    "net"
    "net/smtp"
)

func main() {
    host := "smtpdm.aliyun.com"
    port := 465
    email := "test***@example.net"
    password := "TExxxxxst"
    toEmail := "test1***@example.net"

    header := make(map[string]string)
    header["From"] = "test" + "<" + email + ">"
    header["To"] = toEmail
    header["Subject"] = "Email Title"
    header["Content-Type"] = "text/html; charset=UTF-8"

    body := "This is a test email!"
    message := ""
    for k, v := range header {
        message += fmt.Sprintf("%s: %s\r\n", k, v)
    }
    message += "\r\n" + body

    auth := smtp.PlainAuth(
        "",
        email,
        password,
        host,
    )

    err := SendMailUsingTLS(
        fmt.Sprintf("%s:%d", host, port),
        auth,
        email,
        []string{toEmail},
        []byte(message),
    )

    if err != nil {
        panic(err)
    } else {
        fmt.Println("Send mail success!")
    }
}

//return a smtp client
func Dial(addr string) (*smtp.Client, error) {
    conn, err := tls.Dial("tcp", addr, nil)
    if err != nil {
        log.Println("Dialing Error:", err)
        return nil, err
    }
    // Split the host and port from the string.
    host, _, _ := net.SplitHostPort(addr)
    return smtp.NewClient(conn, host)
}

// See the SendMail() function in net/smtp.
// When you use net. Dial to connect to a TLS (SSL) port, smtp.NewClient() may hang without returning an error.
// If len(to) is greater than 1, recipients from to[1] onwards are treated as BCC recipients.
func SendMailUsingTLS(addr string, auth smtp.Auth, from string,
    to []string, msg []byte) (err error) {

    //create smtp client
    c, err := Dial(addr)
    if err != nil {
        log.Println("Create smpt client error:", err)
        return err
    }
    defer c.Close()

    if auth != nil {
        if ok, _ := c.Extension("AUTH"); ok {
            if err = c.Auth(auth); err != nil {
                log.Println("Error during AUTH", err)
                return err
            }
        }
    }

    if err = c.Mail(from); err != nil {
        return err
    }

    for _, addr := range to {
        if err = c.Rcpt(addr); 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()
}