こんにちは。KOUKIです。
とある企業でGo言語の開発を行っているのですが、最近メール送信機能を担当しました。
「Go言語って、メール送信できるんだっけ?」と思って調べてみたら「smtp」パッケージというものがありました。
これでメールが送れる!と思って以下のプログラムを実行したところ、「Username and Password not accepted」エラーが発生しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
package main import ( "log" "net/smtp" ) // variables to make ExamplePlainAuth compile, without adding // unnecessary noise there. var ( from = "XXXXX@gmail.com" msg = []byte("dummy message") recipients = []string{"XXXXX@gmail.com"} pass = "XXXXX" ) func main() { // hostname is used by PlainAuth to validate the TLS certificate. hostname := "smtp.gmail.com" auth := smtp.PlainAuth(from, from, pass, hostname) err := smtp.SendMail(hostname+":587", auth, from, recipients, msg) if err != nil { log.Fatal(err) } } |
1 2 3 4 |
$ go run main.go 2021/01/21 13:12:35 535 5.7.8 Username and Password not accepted. Learn more at 5.7.8 https://support.google.com/mail/?p=BadCredentials c85sm3685136pfb.37 - gsmtp exit status 1 |
このエラーについて回避策を2つほど検討したので、その内容を記事にしています。
前提
SMTPサーバーに「Gmail」を指定したプログラムでエラーを確認しています。
「hostname := “smtp.gmail.com”」
回避策1: Gmailのセキュリティを下げる
先ほどのエラーの原因は、Gmailのセキュリティが堅牢すぎてGmailアプリ以外からのアクセスをブロックしてしまうことにあります。
そのため、セキュリティ的には問題ありますが、Googleアカウントの「安全性の低いアプリのアクセス」を「オン」にすることで回避します。
決して推奨される方法ではありませんので、自己責任でお願いします。
Gmailにアクセス
Gmailにアクセスしましょう。

Googleアカウントにアクセス
Gmailの「Googleアプリ」からアカウントを選択します。

セキュリティ -> 安全性の低いアプリのアクセス
「セキュリティ」を選択して、ページをスクロールすると「安全性の低いアプリのアクセス」があるはずです。

この設定を「オン」にすることで、メールが飛ぶようになりました。ただ、何度も言うようにセキュリティ的には問題あるので、実験が終わったら元に戻しておくことをおすすめします。
回避策2: そもそもGmailを使わない
ローカルでメール送信機能を試したいというだけならば、Gmailを使う必要がないことに気がつきました。
Dockerイメージのmailhogを使うとSMTPサーバーを簡単に立ち上げられるので、サクッと作ってしまいましょう。
ワークスペースの作成
最初にワークスペースを作成します。
1 2 3 4 |
touch Dockerfile touch docker-compose.yml touch main.go go mod init smtpapp |
Dockerfileの作成
Dockerfileを作成します。
1 2 3 4 5 6 7 8 9 |
FROM golang:1.15-alpine WORKDIR /app COPY . . EXPOSE 80 CMD ["go", "run", "main.go"] |
docker-compose.ymlの作成
次にdocker-compose.ymlを作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
version: "3" services: api: build: . ports: - 80:80 links: - smtp smtp: image: mailhog/mailhog ports: - "1025:1025" - "8025:8025" |
メール送信アプリを作成
Go言語で簡単に書きます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
package main import ( "io/ioutil" "log" "net/smtp" "strings" "golang.org/x/text/encoding/japanese" "golang.org/x/text/transform" ) var ( host = "smtp:1025" from = "test@gmail.com" to = "test@gmail.com" cc = []string{"test@gmail.com"} ) func main() { message := strings.NewReader("test") transformer := japanese.ISO2022JP.NewEncoder() newMessage, _ := ioutil.ReadAll(transform.NewReader(message, transformer)) err := smtp.SendMail(host, nil, from, cc, newMessage) if err != nil { log.Fatal(err) } } |
動作確認
docker-compose upでコンテナを立ち上げるとメールが飛ぶようになっています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
$ docker-compose up smtp_1 | Sending content: { smtp_1 | "ID": "xqyyE4PG8RTW6G2OhCz-sQZK-IGoCtQyO_zFHE0-k_Q=@mailhog.example", smtp_1 | "From": { smtp_1 | "Relays": null, smtp_1 | "Mailbox": "test", smtp_1 | "Domain": "gmail.com", smtp_1 | "Params": "" smtp_1 | }, smtp_1 | "To": [ smtp_1 | { smtp_1 | "Relays": null, smtp_1 | "Mailbox": "test", smtp_1 | "Domain": "gmail.com", smtp_1 | "Params": "" smtp_1 | } smtp_1 | ], smtp_1 | "Content": { smtp_1 | "Headers": { smtp_1 | "Message-ID": [ smtp_1 | "xqyyE4PG8RTW6G2OhCz-sQZK-IGoCtQyO_zFHE0-k_Q=@mailhog.example" smtp_1 | ], smtp_1 | "Received": [ smtp_1 | "from localhost by mailhog.example (MailHog)\r\n id xqyyE4PG8RTW6G2OhCz-sQZK-IGoCtQyO_zFHE0-k_Q=@mailhog.example; Thu, 21 Jan 2021 08:47:07 +0000" smtp_1 | ], smtp_1 | "Return-Path": [ smtp_1 | "\u003ctest@gmail.com\u003e" smtp_1 | ] smtp_1 | }, smtp_1 | "Body": "test", smtp_1 | "Size": 4, smtp_1 | "MIME": null smtp_1 | }, smtp_1 | "Created": "2021-01-21T08:47:07.990836Z", smtp_1 | "MIME": null, smtp_1 | "Raw": { smtp_1 | "From": "test@gmail.com", smtp_1 | "To": [ smtp_1 | "test@gmail.com" smtp_1 | ], smtp_1 | "Data": "test", smtp_1 | "Helo": "localhost" smtp_1 | } smtp_1 | } smtp_1 | smtp_1 | [APIv1] BROADCAST /api/v1/events smtp_api_1 exited with code 0 smtp_1 | [APIv1] KEEPALIVE /api/v1/events smtp_1 | [APIv1] KEEPALIVE /api/v1/events |
terminal上の出力からメール送信に成功したことがわかります。
送信されたメールを確認してみましょう。「http://localhost:8025」をブラウザで開いてみてください。

見ての通り、メールボックスになっていて、ここでメールを確認することができます。

おわりに
Go言語は、メールも飛ばせていいですよね。
しかも、DockerとのコンボでSMTPサーバーを自前で用意できるので、メール機能の実装の練習にはもってこいです。
goroutineと組み合わせて、メール送信を連続で送りつけてみるとかして遊んでみたいと思います。
それでは、また!
コメントを残す
コメントを投稿するにはログインしてください。