Search code examples
goemailsmtpsendgrid

SendGrid SMTP emails are not delivered to CC and BCC addresses in Go


I am trying to send an email with CC & BCC. Emails are not delivered to CC & BCC addresses. But CC addresses are displayed to the recipient's details. A snapshot is given below.

enter image description here

I am using golang net/smtp with SendGrid. My code sample is given below.

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)

    err := smtp.SendMail(config.Config.EmailClientHost+":"+config.Config.EmailClientPort, smtpAuth, email.From, email.To, emailMessageBytes)

    if err != nil {
        log.Printf("smtp error: %s", err)
        return err
    }

    return nil
}

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

    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()
}

Please help me. Advance thanks :)


Solution

  • Under the covers, smtp.SendMail calls smtp.Client.Rcpt for each to recipient. The to slice directs who will actually receive the email. The addressees in the body of the email is purely informational - in fact they don't even need to match the real addressee info.

    So to fix your addressing issue, you need to collect all to, cc & bcc addressees:

    var all []string
    for _, a := range [][]string{email.To, email.CC, email.BCC} {
        all = append(all, a)
    }
    
    err := smtp.SendMail(
        config.Config.EmailClientHost+":"+config.Config.EmailClientPort,
        smtpAuth,
        email.From,
        all, //email.To,
        emailMessageBytes,
    )
    

    also since every recipient receives the body of the e-mail, bcc users should not be listed in the body, for obvious privacy reasons.

    So remove this:

    // if len(m.BCC) > 0 {
    //    buf.WriteString(fmt.Sprintf("Bcc: %s\r\n", strings.Join(m.BCC, ",")))
    //}