tencent cloud

Sending Email with Attachment
Last updated: 2023-12-22 10:28:23
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()
}


Was this page helpful?
You can also Contact Sales or Submit a Ticket for help.
Yes
No

Feedback