tencent cloud


Sending Email with Attachment

Last updated: 2022-09-09 14:59:12

    The method of sending an email with an attachment through SMTP is to construct the content of a MIME-formatted email.

    Email MIME Format

    For more information, see MIME Protocol.


    A MIME message consists of two parts: email header and email body.

    Email Header

    The email header contains important information such as sender, recipient, subject, time, MIME version, and body type.


    Each piece of information is called a field, which consists of a domain followed by ":" and the information content and can be in one or multiple lines.

    • The first line of a field must be written "to the left", i.e., without whitespace characters (spaces and tabs) on the left.
    • The next lines must start with whitespace characters, one of which must not be inherent in the message itself (that is, it needs to be filtered out during decoding).

    Blank lines are not allowed in the email header. If the first line is blank, some emails cannot be recognized by certain email client software, and the original code is displayed.

    For example:

    Content Example
    Date Mon, 29 Jun 2009 18:39:03 +0800
    From abc@123.com
    To abc1@123.com
    BCC abc3@123.com
    Subject test
    Message-ID 123@123.com
    Mime-Version 1.0
    Field Description
    Bcc Blind carbon copy address
    Cc Copy address
    Content-Transfer-Encoding Content transfer encoding method
    Content-Type Content type
    Date Date and time
    Delivered-To Recipient address
    From Sender address
    Message-ID Message ID
    MIME-Version MIME version
    Received Transfer path
    Reply-To Reply-to address
    Return-Path Reply-to address
    Subject Subject
    To Recipient address

    Email Body

    Field Description
    Content-ID Content ID
    Content-Transfer-Encoding Content transfer encoding method
    Content-Location Content location (path)
    Content-Base Content base location
    Content-Disposition Content disposition method
    Content-Type Content type

    Some fields have parameters in addition to values. Value and parameter as well as parameter and parameter are separated with ";". Parameter name and parameter value are separated with "=".

    • The email body contains the content of the email, whose type is indicated by the Content-Type field in the email header.


      Common simple types include:

      • text/plain (plain text)
      • text/html (hypertext)
    • The multipart type is the essence of MIME emails. The email body is divided into multiple parts, each of which consists of part header and part body separated by a blank line.

    • There are three common multipart types:

      • multipart/mixed
      • multipart/related
      • multipart/alternative
        The meaning and use of each of these types can be seen from their names. The hierarchical relationship between them can be summarized as shown below:

        If you want to add attachments to an email, you must define the multipart/mixed part. If there are embedded resources, you must define at least the multipart/related part; if plain text and hypertext coexist, you must define at least the multipart/alternative part.

        The number of attachments should not exceed 10, the size of a single attachment should not exceed 4 MB, and the total size of all attachments should not exceed 8 MB. For more information, see Data Structure.

    Sample Code

    package main
    import (

    // Test465Attachment for port 465
    func Test465Attachment() error {
    boundary := "GoBoundary"
    host := "sg-smtp.qcloudmail.com"
    port := 465
    email := "abc@cd.com"
    password := "***"
    toEmail := "test@test123.com"
    header := make(map[string]string)
    header["From"] = "test " + "<" + email + ">"
    header["To"] = toEmail
    header["Subject"] = "Test465Attachment"
    header["Content-Type"] = "multipart/mixed;boundary=" + boundary
    // This field is not used for the time being. Pass in `1.0` by default
    header["Mime-Version"] = "1.0"
    // This field is not used for the time being
    header["Date"] = time.Now().String()
    bodyHtml := "\n\n\n<meta charset="\"utf-8\"">\n<title>hello world</title>\n\n\n " +
    "<h1>My first heading</h1>\n <p>My first paragraph.</p>\n\n"
    message := ""
    for k, v := range header {
    message += fmt.Sprintf("%s: %s\r\n", k, v)
    buffer := bytes.NewBuffer(nil)
    contentType := "Content-Type: text/html" + "; charset=UTF-8"
    body := "\r\n--" + boundary + "\r\n"
    body += "Content-Type:" + contentType + "\r\n"
    body += "\r\n" + bodyHtml + "\r\n"

    attachment := "\r\n--" + boundary + "\r\n"
    attachment += "Content-Transfer-Encoding:base64\r\n"
    attachment += "Content-Disposition:attachment\r\n"
    attachment += "Content-Type:" + "application/octet-stream" + ";name=\"" + mime.BEncoding.Encode("UTF-8",
    "./go.mod") + "\"\r\n"
    writeFile(buffer, "./go.mod")
    // Multiple attachments can be spliced at the end. There can be 10 attachments at most, each of which cannot exceed 5 MB in size. The TOTAL size of all attachments cannot exceed 8–9 MB; otherwise, EOF will be returned
    attachment1 := "\r\n--" + boundary + "\r\n"
    attachment1 += "Content-Transfer-Encoding:base64\r\n"
    attachment1 += "Content-Disposition:attachment\r\n"
    attachment1 += "Content-Type:" + "application/octet-stream" + ";name=\"" + mime.BEncoding.Encode("UTF-8",
    "./bbbb.txt") + "\"\r\n"
    writeFile(buffer, "./bbbb.txt")
    defer func() {
    if err := recover(); err != nil {

    buffer.WriteString("\r\n--" + boundary + "--")
    message += "\r\n" + body
    auth := smtp.PlainAuth(
    err := SendMailWithTLS(
    fmt.Sprintf("%s:%d", host, port),
    if err != nil {
    fmt.Println("Send email error:", err)
    } else {
    fmt.Println("Send mail success!")
    return err

    // Dial return a smtp client
    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

    host, _, _ := net.SplitHostPort(addr)
    return smtp.NewClient(conn, host)

    // SendMailWithTLS send email with tls
    func SendMailWithTLS(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 smtp 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()

    // writeFile read file to buffer
    func writeFile(buffer *bytes.Buffer, fileName string) {
    file, err := ioutil.ReadFile(fileName)
    if err != nil {
    payload := make([]byte, base64.StdEncoding.EncodedLen(len(file)))
    base64.StdEncoding.Encode(payload, file)
    for index, line := 0, len(payload); index < line; index++ {
    if (index+1)%76 == 0 {

    func main() {
    Contact Us

    Contact our sales team or business advisors to help your business.

    Technical Support

    Open a ticket if you're looking for further assistance. Our Ticket is 7x24 avaliable.

    7x24 Phone Support