You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Go语言通过SendGrid SMTP发送邮件时,CC与BCC地址无法收到邮件

解决Go net/smtp结合SendGrid发送邮件时CC/BCC无法收到的问题

我来帮你搞定这个问题!你遇到的CC和BCC收不到邮件,但CC地址显示在收件详情里的情况,核心原因是对net/smtp.SendMail的工作机制理解有误,咱们一步步来修正:

问题根源

Go标准库的smtp.SendMail方法的第四个参数(to []string)对应的是SMTP协议中的**RCPT TO指令列表**——这才是SMTP服务器实际要投递邮件的目标地址。你现在只传入了email.To,所以CC和BCC地址根本没被纳入投递范围。而你在邮件头里添加的Cc和Bcc字段,只是用来在邮件客户端显示用的,不会触发实际的邮件投递。

另外还有个小问题:BCC的本意是密送,绝对不能出现在邮件头里,否则所有收件人都能看到密送地址,完全失去了密送的意义。

代码修正方案

1. 合并所有收件人到SendMail的目标列表

我们需要把To、CC、BCC的地址合并成一个完整的收件人列表(记得去重,避免重复发送),传给SendMail的第四个参数:

修改SendEmail函数:

func SendEmail() error {
	email := entity.Email{
		From: "info@somewhere.cloud",
		To: []string{"crajuceveifre-5717@yopmail.com"},
		ReplyTo: "dileulobugre-7335@yopmail.com",
		Subject: "Email Subject",
		Body: "Email Body",
		BCC: []string{"lecrecezufeu-9078@yopmail.com"},
		CC: []string{"houcroissezitri-3721@yopmail.com"},
	}
	emailMessageBytes := ToBytes(email)
	smtpAuth := smtp.PlainAuth("", "apikey", config.Config.EmailClientApiKey, config.Config.EmailClientHost)

	// 合并To、CC、BCC到实际投递列表,去重避免重复发送
	allRecipients := make(map[string]struct{})
	for _, addr := range email.To {
		allRecipients[addr] = struct{}{}
	}
	for _, addr := range email.CC {
		allRecipients[addr] = struct{}{}
	}
	for _, addr := range email.BCC {
		allRecipients[addr] = struct{}{}
	}
	// 转换为切片
	recipientSlice := make([]string, 0, len(allRecipients))
	for addr := range allRecipients {
		recipientSlice = append(recipientSlice, addr)
	}

	err := smtp.SendMail(config.Config.EmailClientHost+":"+config.Config.EmailClientPort, smtpAuth, email.From, recipientSlice, emailMessageBytes)
	if err != nil {
		log.Printf("smtp error: %s", err)
		return err
	}
	return nil
}

2. 移除邮件头中的BCC字段

修改ToBytes函数,删掉添加Bcc头的代码:

func ToBytes(m entity.Email) []byte {
	buf := bytes.NewBuffer(nil)
	buf.WriteString(fmt.Sprintf("From: %s\r\n", m.From))
	buf.WriteString(fmt.Sprintf("To: %s\r\n", strings.Join(m.To, ",")))
	buf.WriteString(fmt.Sprintf("Reply-To: %s\r\n", m.ReplyTo))
	if len(m.CC) > 0 {
		buf.WriteString(fmt.Sprintf("Cc: %s\r\n", strings.Join(m.CC, ",")))
	}
	// 删掉下面这段Bcc头的代码,因为密送地址不能出现在邮件头里
	// if len(m.BCC) > 0 {
	// 	buf.WriteString(fmt.Sprintf("Bcc: %s\r\n", strings.Join(m.BCC, ",")))
	// }
	buf.WriteString(fmt.Sprintf("Subject: %s\r\n", m.Subject))
	buf.WriteString("MIME-Version: 1.0\n")
	writer := multipart.NewWriter(buf)
	boundary := writer.Boundary()
	buf.WriteString(fmt.Sprintf("Content-Type: multipart/mixed; boundary=%s\n\n", boundary))
	buf.WriteString(fmt.Sprintf("--%s\n", boundary))
	buf.WriteString("Content-Type: text/html; charset=utf-8\n")
	buf.WriteString(m.Body)
	buf.WriteString(fmt.Sprintf("\n\n--%s\n", boundary))
	return buf.Bytes()
}

为什么这样改?

  • SMTP协议规则:只有RCPT TO指定的地址才会收到邮件,邮件头的Cc/Bcc仅用于显示,不决定投递目标。
  • BCC的特性:密送地址必须隐藏,不能出现在邮件头中,否则所有收件人都能看到,违背了密送的设计意图。
  • 去重处理:防止同一个地址同时出现在To/CC/BCC中时被重复发送。

这样修改后,CC和BCC地址就能正常收到邮件,同时CC地址会显示在收件详情里,BCC地址则完全隐藏,符合预期效果。

内容的提问来源于stack exchange,提问作者Md Zobayer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 21:22:45