tencent cloud

Feedback

Sending Email with Attachment

Last updated: 2023-12-22 10:28:23
    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.
    Note:
    A MIME message consists of two parts: email header and email body.

    Email Header

    Note:
    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.
    Note:
    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.
    Note:
    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 (
    "bytes"
    "crypto/tls"
    "encoding/base64"
    "fmt"
    "io/ioutil"
    "log"
    "mime"
    "net"
    "net/smtp"
    "time"
    )
    
    // 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 := "<!DOCTYPE html>\\n<html>\\n<head>\\n<meta charset=\\"utf-8\\">\\n<title>hello world</title>\\n</head>\\n<body>\\n " +
    "<h1>My first heading</h1>\\n <p>My first paragraph.</p>\\n</body>\\n</html>"
    message := ""
    for k, v := range header {
    message += fmt.Sprintf("%s: %s\\r\\n", k, v)
    }
    buffer := bytes.NewBuffer(nil)
    buffer.WriteString(message)
    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"
    buffer.WriteString(body)
    
    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"
    buffer.WriteString(attachment)
    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"
    buffer.WriteString(attachment1)
    writeFile(buffer, "./bbbb.txt")
    defer func() {
    if err := recover(); err != nil {
    log.Fatalln(err)
    }
    }()
    
    buffer.WriteString("\\r\\n--" + boundary + "--")
    message += "\\r\\n" + body
    auth := smtp.PlainAuth(
    "",
    email,
    password,
    host,
    )
    err := SendMailWithTLS(
    fmt.Sprintf("%s:%d", host, port),
    auth,
    email,
    []string{toEmail},
    buffer.Bytes(),
    )
    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 {
    panic(err.Error())
    }
    payload := make([]byte, base64.StdEncoding.EncodedLen(len(file)))
    base64.StdEncoding.Encode(payload, file)
    buffer.WriteString("\\r\\n")
    for index, line := 0, len(payload); index < line; index++ {
    buffer.WriteByte(payload[index])
    if (index+1)%76 == 0 {
    buffer.WriteString("\\r\\n")
    }
    }
    }
    
    func main() {
    Test465Attachment()
    }
    
    
    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