📘

Goでドコモメール送信

2020/10/28に公開

Goでドコモのキャリアメールを送信するサンプル実装

package main

import (
	"crypto/tls"
	"encoding/base64"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/mail"
	"net/smtp"
	"strings"

	"golang.org/x/text/encoding/japanese"
	"golang.org/x/text/transform"
)

func main() {
	send()
}

func send() {
	from := mail.Address{"", "from@docomo.ne.jp"}
	to := mail.Address{"", "to@gmail.com"}

	message := createMessage(from, to)

	servername := "smtp.spmode.ne.jp:465"

	host, _, _ := net.SplitHostPort(servername)

	auth := smtp.PlainAuth("", "account_id", "password", host)

	tlsconfig := &tls.Config{
		InsecureSkipVerify: true,
		ServerName:         host,
	}

	conn, err := tls.Dial("tcp", servername, tlsconfig)
	if err != nil {
		log.Panic(err)
	}

	c, err := smtp.NewClient(conn, host)
	if err != nil {
		log.Panic(err)
	}

	if err = c.Auth(auth); err != nil {
		log.Panic(err)
	}

	if err = c.Mail(from.Address); err != nil {
		log.Panic(err)
	}

	if err = c.Rcpt(to.Address); err != nil {
		log.Panic(err)
	}

	w, err := c.Data()
	if err != nil {
		log.Panic(err)
	}

	_, err = w.Write([]byte(message))
	if err != nil {
		log.Panic(err)
	}

	err = w.Close()
	if err != nil {
		log.Panic(err)
	}

	err = c.Quit()
	if err != nil {
		log.Panic(err)
	}

}

func createMessage(from, to mail.Address) string {
	cc := []string{"hoge+cc1@gmail.com", "hoge+cc2@gmail.com"}
	delimeter := "**=myohmy689407924327"
	subj := "サンプルメール"
	htmlBody := "<html><body><h1>こんにちわ。</h1><br><h3>ワールド</h3></body></html>"
	textBody := "Hello World"

	sampleMsg := fmt.Sprintf("From: %s\r\n", from.String())
	sampleMsg += fmt.Sprintf("To: %s\r\n", to.String())
	if len(cc) > 0 {
		sampleMsg += fmt.Sprintf("Cc: %s\r\n", strings.Join(cc, ";"))
	}
	subject, err := toISO2022JP(subj)
	if err != nil {
		log.Panic(err)
	}

	sampleMsg += "Subject: " + string(subject) + "\r\n"

	sampleMsg += "MIME-Version: 1.0\r\n"
	sampleMsg += fmt.Sprintf("Content-Type: multipart/mixed; boundary=\"%s\"\r\n", delimeter)

	if htmlBody != "" {
		sampleMsg += fmt.Sprintf("\r\n--%s\r\n", delimeter)
		sampleMsg += "Content-Type: text/html; charset=\"utf-8\"\r\n"
		sampleMsg += "Content-Transfer-Encoding: base64\r\n"
		sampleMsg += fmt.Sprintf("\r\n%s", base64.StdEncoding.EncodeToString([]byte(htmlBody))+"\r\n")
	} else if textBody != "" {
		sampleMsg += fmt.Sprintf("\r\n--%s\r\n", delimeter)
		sampleMsg += "Content-Type: text/plain; charset=\"utf-8\"\r\n"
		sampleMsg += "Content-Transfer-Encoding: base64\r\n"
		sampleMsg += fmt.Sprintf("\r\n%s", base64.StdEncoding.EncodeToString([]byte(textBody))+"\r\n")
	}

	attachmentFile, err := ioutil.ReadFile("./attachment.pdf")
	if err != nil {
		log.Panic(err)
	}
	sampleMsg += fmt.Sprintf("\r\n--%s\r\n", delimeter)
	sampleMsg += "Content-Type: " + http.DetectContentType(attachmentFile) + "; charset=\"utf-8\"\r\n"
	sampleMsg += "Content-Transfer-Encoding: base64\r\n"
	sampleMsg += "Content-Disposition: attachment;filename=\"" + base64.StdEncoding.EncodeToString([]byte("attachment.pdf")) + "\"\r\n"

	sampleMsg += "\r\n" + base64.StdEncoding.EncodeToString(attachmentFile)

	sampleMsg += fmt.Sprintf("\r\n--%s\r\n", delimeter)

	return sampleMsg
}

func toISO2022JP(str string) ([]byte, error) {
	reader := strings.NewReader(str)
	transformer := japanese.ISO2022JP.NewEncoder()

	return ioutil.ReadAll(transform.NewReader(reader, transformer))
}

Discussion