tencent cloud

Go 调用示例

Download
聚焦模式
字号
最后更新时间: 2026-05-12 16:00:22
以下代码示例,Go 语言(版本为1.16)通过 SMTP 发送邮件:


// Package main 提供腾讯云邮件推送(SES)SMTP 协议发信的 Go 语言示例。
//
// 本代码演示了如何通过 SMTP 协议(端口 465,SSL/TLS 加密)向腾讯云邮件推送服务
// 发起发信请求。整体流程分为以下几步:
// 1. 准备发信参数(发信人、收件人、抄送、密送、主题、正文等);
// 2. 按 RFC 822 格式拼装邮件 Header 与 Body(Body 使用 Base64 编码);
// 3. 通过 tls.Dial 与 SMTP 服务器建立加密连接;
// 4. 通过 PlainAuth 完成身份认证;
// 5. 依次执行 MAIL FROM、RCPT TO、DATA 等 SMTP 命令完成投递。
//
// 使用前请先在腾讯云邮件推送控制台完成以下准备工作:
// - 创建并验证发信域名(Sender Domain);
// - 创建发信地址(Sender Address),并开启 SMTP 发信;
// - 在控制台「SMTP 密码」处生成专用密码(注意:不是腾讯云账号密码);
// - 确认发信地址有可用的发信额度。
//
// 依赖:标准库 net/smtp、crypto/tls,无需引入第三方包。
package main

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

// Test465 演示通过 465 端口(SSL/TLS)发送一封 HTML 格式邮件。
//
// 流程:
// 1. 配置 SMTP 服务器地址、端口、发信账号、SMTP 密码;
// 2. 构造邮件头(From / To / Cc / Bcc / Subject / Content-Type 等);
// 3. 将邮件正文 Base64 编码后拼接到 Header 之后(Header 与 Body 之间需要一个空行);
// 4. 使用 smtp.PlainAuth 创建 PLAIN 认证对象;
// 5. 调用 SendMailWithTLS 通过 TLS 连接完成投递。
//
// 返回值:发送成功返回 nil,失败返回具体错误。
func Test465() error {
// SMTP 服务器地址,腾讯云邮件推送固定为 smtp.qcloudmail.com
host := "smtp.qcloudmail.com"
// SMTP 端口:465 表示 SSL/TLS 加密连接;
// 如需使用 STARTTLS,可改为 25 端口,但代码中的 tls.Dial 也需相应调整为 net.Dial + StartTLS。
port := 465

// email:控制台创建并验证通过的发信地址(Sender Address),必须与 SMTP 密码所属账号一致。
email := "abc@cd.com"
// password:在控制台「SMTP 设置」中为该发信地址单独生成的 SMTP 密码,
// 不是腾讯云账号登录密码,也不是 API 密钥。
password := "****"

// 收件人地址(必填,至少一个)
toEmail := "test@test123.com"
// 抄送地址(可选)
ccEmail := "cc@test123.com"
// 密送地址(可选)
bccEmail := "bcc@test123.com"

// 构造邮件 Header。SMTP 协议要求 Header 字段以 "Key: Value\\r\\n" 形式书写,
// 所有 Header 结束后需要一个空行("\\r\\n")再跟 Body。
header := make(map[string]string)
// From 推荐写成 "显示名 <发信地址>" 的形式,显示名会作为收件箱中展示的发件人昵称。
header["From"] = "test " + "<" + email + ">"
header["To"] = toEmail
header["Cc"] = ccEmail
header["Bcc"] = bccEmail
// 邮件主题;如包含中文,建议进行 RFC 2047 编码(=?UTF-8?B?...?=),本示例为纯英文示例所以未编码。
header["Subject"] = "test subject"

// Content-Type 指定正文类型为 HTML,并声明字符集为 UTF-8。
header["Content-Type"] = "text/html; charset=UTF-8"
// Content-Transfer-Encoding 指定正文的传输编码方式,这里用 base64
// 可避免中文/特殊字符在 SMTP 传输过程中被截断或损坏。
header["Content-Transfer-Encoding"] = "base64"

// HTML 格式正文示例
body := "<!DOCTYPE html>\\n<html>\\n<head>\\n<meta charset=\\"utf-8\\">\\n<title>hello world</title>\\n</head>\\n<body>\\n " +
"<h1>我的第一个标题</h1>\\n <p>我的第一个段落。</p>\\n</body>\\n</html>"

// 如需发送纯文本邮件,可注释掉上面的 HTML 配置,并启用以下两行:
//header["Content-Type"] = "text/plain; charset=UTF-8"
//body := "test body"

// 拼装最终的 SMTP 报文:先把 Header 全部拼成 "Key: Value\\r\\n",
// 再用空行分隔,最后接上 Base64 编码后的 Body。
message := ""
for k, v := range header {
message += fmt.Sprintf("%s: %s\\r\\n", k, v)
}
message += "\\r\\n" + base64.StdEncoding.EncodeToString([]byte(body))

// 创建 PLAIN 认证对象。
// 第 1 个参数 identity 通常留空,第 2 个为用户名(即发信地址),
// 第 3 个为 SMTP 密码,第 4 个为 host(用于服务端校验)。
auth := smtp.PlainAuth(
"",
email,
password,
host,
)

// 调用 TLS 版发信函数,传入服务器地址、认证对象、发件人、收件人列表与原始报文。
// 注意:to 列表用于 SMTP 的 RCPT TO 命令,决定邮件实际投递到哪些邮箱;
// 如需让抄送/密送真实收到邮件,必须把 ccEmail / bccEmail 也加入此列表。
err := SendMailWithTLS(
fmt.Sprintf("%s:%d", host, port),
auth,
email,
[]string{toEmail},
[]byte(message),
)
if err != nil {
fmt.Println("Send email error:", err)
} else {
fmt.Println("Send mail success!")
}
return err
}

// Dial 与 SMTP 服务器建立 TLS 加密连接,并返回一个可用的 *smtp.Client。
//
// 参数:
// - addr:服务器地址,格式为 "host:port",例如 "smtp.qcloudmail.com:465"。
//
// 说明:
// - 标准库 smtp.Dial 默认使用明文连接,对于 465 端口必须先建立 TLS 通道再封装成 SMTP 客户端,
// 因此本函数使用 tls.Dial 替代 net.Dial。
// - 第二个参数为 *tls.Config,传 nil 表示使用默认配置(会校验服务端证书)。
// 如需跳过证书校验(不推荐生产使用),可传 &tls.Config{InsecureSkipVerify: true}。
func Dial(addr string) (*smtp.Client, error) {
conn, err := tls.Dial("tcp", addr, nil)
if err != nil {
log.Println("tls.Dial Error:", err)
return nil, err
}

// smtp.NewClient 需要 host(不含端口)用于 EHLO/HELO 握手。
host, _, _ := net.SplitHostPort(addr)
return smtp.NewClient(conn, host)
}

// SendMailWithTLS 通过 TLS 加密的 SMTP 连接完成一次完整的邮件投递。
//
// 参数:
// - addr:SMTP 服务器地址,格式 "host:port"。
// - auth:SMTP 认证对象,可由 smtp.PlainAuth 创建;如不需认证可传 nil。
// - from:MAIL FROM 命令使用的发件人地址,应与认证账号一致。
// - to: RCPT TO 命令使用的收件人列表,包含主送、抄送、密送的所有真实收件人。
// - msg: 完整的邮件报文(Header + 空行 + Body),格式需符合 RFC 822。
//
// 处理步骤:
// 1. 通过 Dial 建立 TLS + SMTP 连接;
// 2. 若服务端支持 AUTH 扩展,则执行身份认证;
// 3. 依次执行 MAIL FROM、RCPT TO、DATA 命令;
// 4. 写入邮件正文并关闭数据流;
// 5. 调用 QUIT 命令优雅关闭会话。
//
// 任何一步失败都会立即返回对应错误。
func SendMailWithTLS(addr string, auth smtp.Auth, from string,
to []string, msg []byte) (err error) {
// 1. 建立 TLS 加密连接,得到 SMTP 客户端
c, err := Dial(addr)
if err != nil {
log.Println("Create smtp client error:", err)
return err
}
// 确保连接最终被关闭,避免连接泄漏
defer c.Close()

// 2. 如果传入了 auth,并且服务端通过 EHLO 声明支持 AUTH 扩展,则执行认证
if auth != nil {
if ok, _ := c.Extension("AUTH"); ok {
if err = c.Auth(auth); err != nil {
log.Println("Error during AUTH", err)
return err
}
}
}

// 3. 发送 MAIL FROM 命令,告知服务器发件人
if err = c.Mail(from); err != nil {
return err
}
// 4. 依次发送 RCPT TO 命令,告知服务器每一个收件人
for _, addr := range to {
if err = c.Rcpt(addr); err != nil {
return err
}
}

// 5. 发送 DATA 命令并获取写入流,用于写入邮件正文(Header + Body)
w, err := c.Data()
if err != nil {
return err
}
_, err = w.Write(msg)
if err != nil {
return err
}
// 关闭写入流,标志正文输入结束(SMTP 协议中以 "\\r\\n.\\r\\n" 表示结束)
err = w.Close()
if err != nil {
return err
}

// 6. 发送 QUIT 命令,与服务器优雅地结束会话
return c.Quit()
}

// main 是入口,直接调用 Test465 触发一次发信。
// 实际接入业务时,建议把发信参数(账号、密码、收件人等)抽离为配置或函数入参,
// 并对 Test465 中的错误进行更细粒度的处理与重试。
func main() {
Test465()
}



帮助和支持

本页内容是否解决了您的问题?

填写满意度调查问卷,共创更好文档体验。

文档反馈