PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0

Sunday, October 23, 2022

[FIXED] How to make the attached pdf file be downloadable when sending email with go/smtp?

 October 23, 2022     base64, email, go, pdf, smtp     No comments   

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.

enter image description here

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)
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Newer Post Older Post Home

0 Comments:

Post a Comment

Note: Only a member of this blog may post a comment.

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
Comments
Atom
Comments

Copyright © PHPFixing