Todos los productos
Search
Centro de documentos

Direct Mail:Llamar a SMTP con Go: código de ejemplo

Última actualización: Sep 03, 2026

Envíe correos electrónicos desde una aplicación en Go mediante el servicio SMTP de Direct Mail. Se incluyen dos ejemplos completos que abarcan el puerto 80 (conexión sin cifrar con autenticación PLAIN o LOGIN) y el puerto 465 (TLS implícito).

Direct Mail ofrece dos endpoints SMTP. Use el puerto 80 para una conexión sin cifrar con autenticación PLAIN o LOGIN. Use el puerto 465 para TLS implícito, donde el protocolo de enlace TLS se realiza antes de cualquier comando SMTP. Ambos ejemplos se verificaron en Go 1.16.5 y usan smtpdm.aliyun.com como host SMTP.

Requisitos previos

Antes de empezar, asegúrese de contar con lo siguiente:

  • Una dirección de remitente verificada y configurada en la consola de Direct Mail

  • La contraseña SMTP correspondiente a dicha dirección de remitente

Uso del puerto 80

El siguiente ejemplo envía un correo electrónico en formato HTML con destinatarios en los campos To, CC y BCC. La función MergeSlice combina las tres listas de destinatarios en una sola lista para el sobre SMTP. Esto es obligatorio porque el comando RCPT TO de SMTP determina qué buzones reciben el mensaje, independientemente de lo que indiquen los encabezados del correo.

Reemplace las cadenas de marcador de posición en main() con su dirección de remitente y la contraseña SMTP obtenidas en la consola de Direct Mail.

Nota

Para enviar mensajes a través de una conexión cifrada, use el ejemplo del puerto 465 que se muestra más adelante. No emplee el código del puerto 80 para conexiones TLS.

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
}

Nota de compatibilidad con Go 1.9.2

Nota

Go 1.9.2 exige autenticación cifrada y rechaza una llamada simple a PlainAuth con un error de "unencrypted connection". Para solucionar esto, reemplace la llamada a smtp.PlainAuth por la implementación personalizada de LoginAuth que se presenta a continuación.

Agregue la siguiente implementación de LoginAuth a su archivo:

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
}

Luego, reemplace la línea de autenticación en main() con:

auth := LoginAuth(user, password)

Uso del puerto 465

El puerto 465 usa TLS implícito: el protocolo de enlace TLS ocurre antes de cualquier comando SMTP, por lo que no es posible usar directamente la función integrada SendMail de net/smtp. Este ejemplo define una función personalizada llamada Dial que abre una conexión TLS mediante tls.Dial, así como una función SendMailUsingTLS que gestiona la sesión SMTP de forma manual.

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!")
    }
}

// Dial opens an implicit TLS connection and returns an 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 address string.
    host, _, _ := net.SplitHostPort(addr)
    return smtp.NewClient(conn, host)
}

// SendMailUsingTLS sends an email over an implicit TLS connection.
// 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 the 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()
}