Issue
I try to send the email containing pdf file by using Go and smtp.office365.com.
I found the following page and can send the email with pdf file.
https://zetcode.com/golang/email-smtp/
However, the pdf file is encoded as base64 as shown in the attached image below.
Is there any solution to make the attached pdf file be downloadable just like ordinary mail(attaching file with gmail, outlook, etc.)?
Here is the Go code that I used.
package main
import (
"bytes"
"encoding/base64"
"errors"
"fmt"
"io/ioutil"
"log"
"net/smtp"
"strconv"
"strings"
)
type loginAuth struct {
username, password string
}
type Mail struct {
Sender string
To []string
Subject string
Body string
}
// LoginAuth is used for smtp login auth
func LoginAuth(username, password string) smtp.Auth {
return &loginAuth{username, password}
}
func (a *loginAuth) Start(server *smtp.ServerInfo) (string, []byte, error) {
return "LOGIN", []byte(a.username), nil
}
func (a *loginAuth) Next(fromServer []byte, more bool) ([]byte, error) {
if more {
switch string(fromServer) {
case "Username:":
return []byte(a.username), nil
case "Password:":
return []byte(a.password), nil
default:
return nil, errors.New("Unknown from server")
}
}
return nil, nil
}
func BuildMail(mail Mail, filename string) []byte {
var buf bytes.Buffer
buf.WriteString(fmt.Sprintf("From: %s\r\n", mail.Sender))
buf.WriteString(fmt.Sprintf("To: %s\r\n", strings.Join(mail.To, ";")))
buf.WriteString(fmt.Sprintf("Subject: %s\r\n", mail.Subject))
boundary := "my-boundary-779"
buf.WriteString("MIME-Version: 1.0\r\n")
buf.WriteString(fmt.Sprintf("Content-Type: multipart/mixed; boundary=%s\n", boundary))
buf.WriteString(fmt.Sprintf("\r\n--%s\r\n", boundary))
buf.WriteString("Content-Type: text/plain; charset=\"utf-8\"\r\n")
buf.WriteString(fmt.Sprintf("\r\n%s", mail.Body))
buf.WriteString(fmt.Sprintf("\r\n--%s\r\n", boundary))
buf.WriteString("Content-Type: text/plain; charset=\"utf-8\"\r\n")
buf.WriteString("Content-Transfer-Encoding: base64\r\n")
buf.WriteString("Content-Disposition: attachment; filename=" + filename + "\r\n")
buf.WriteString("Content-ID: <" + filename + ">\r\n\r\n")
data := readFile(filename)
b := make([]byte, base64.StdEncoding.EncodedLen(len(data)))
base64.StdEncoding.Encode(b, data)
buf.Write(b)
buf.WriteString(fmt.Sprintf("\r\n--%s", boundary))
buf.WriteString("--")
return buf.Bytes()
}
func readFile(fileName string) []byte {
data, err := ioutil.ReadFile(fileName)
if err != nil {
log.Fatal(err)
}
return data
}
func Mail_send(sender string, sender_pwd string, server string, port int, to []string, headerSubject string, body string, filename string) {
auth := LoginAuth(sender, sender_pwd)
request := Mail{
Sender: sender,
To: to,
Subject: headerSubject,
Body: body,
}
data := BuildMail(request, filename)
err := smtp.SendMail(server+":"+strconv.Itoa(port), auth, sender, to, data)
if err != nil {
log.Fatalln("Error")
return
}
log.Fatalln("Success")
}
func main() {
server := "smtp.office365.com"
port := 587
sender := "my email"
password := "my pwd"
receiver := []string{"EmailIWantToSend@gmail.com"}
title := "TEST\r\n"
body := "test\r\n"
attach_filename := "report.pdf"
Mail_send(sender, password, server, port, receiver, title, body, attach_filename)
}
Here is the email that I received.
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary=my-boundary-779
--my-boundary-779
Content-Type: text/plain; charset="utf-8"
test
--my-boundary-779
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename=report.pdf
Content-ID: <report.pdf>
JVBERi0xLjMKMyAwIG9iago8PC9UeXBlIC9QYWdlCi9QYXJlbnQgMSAwIFIKL1Jlc291cmNlcyAyIDAgUgovQ29udGVudHMgNCAwIFI+PgplbmRvYmoKNCAwIG9iago8PC9GaWx0ZXIgL0ZsYXRlRGVjb2RlIC9MZW5ndGggMTcyMz4+CnN0cmVhbQp4AZyaS2/dRg+G9/4Vs/w
... // I omit since base64 string is too long.
AgbiAKMDAwMDAwMzc0NSAwMDAwMCBuIAowMDAwMDA0MDUzIDAwMDAwIG4gCjAwMDAwMDQxNjYgMDAwMDAgbiAKdHJhaWxlcgo8PAovU2l6ZSAxMQovUm9vdCAxMCAwIFIKL0luZm8gOSAwIFIKPj4Kc3RhcnR4cmVmCjQyNjQKJSVFT0YK
--my-boundary-779--
I want that the email receiver can download the attached pdf file directly, not the base64 string.
Solution
As suspected, you break your message headers with an empty line. A complete message consists of header fields and a body separated by an empty line, which looks as follows:
From: Alice <alice@example.org>
To: Bob <bob@example.com>
Cc: Carol <carol@example.com>
Subject: A simple example message
Date: Fri, 07 Oct 2022 16:44:37 +0200
Message-ID: <unique-identifier@example.org>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Hello Bob,
I think we should switch our roles.
How about you contact me from now on?
Best regards,
Alice
You, however, end the subject with a newline (title := "TEST\r\n"
) and then write another newline (buf.WriteString(fmt.Sprintf("Subject: %s\r\n", mail.Subject))
). As a consequence, MIME-Version: 1.0
is considered to be part of the message body instead of the header. Try it again without the newline at the end of title
. And as Steffen Ullrich noted, you should replace Content-Type: text/plain; charset="utf-8"
with Content-Type: application/pdf
when you send a PDF. (The charset is also not necessary.)
Answered By - Kaspar Etter Answer Checked By - Robin (PHPFixing Admin)
0 Comments:
Post a Comment
Note: Only a member of this blog may post a comment.