inthisfucking.world

💩🌎

GCPの環境からGoogle Workspace SMTP Relay Serviceを使ってメールを送信する

Google Workspaceのライセンスを持っている場合は、Google Workspaceが提供しているSMTP relay serviceを使ってメールを送信することができます。それを使って、GCPの環境からメールを送信する方法を記載します。

GCPの環境からメールを送信する場合は、通常SendGridなどのサービスを使用すると思います。それでなんの問題もありませんが、Google Workspaceのライセンスが付与されたユーザは、Google Workspaceが提供するSMTP relay serviceを使ってメールを送信できます。

この記事では、GCPの環境からGoogle WorkspaceのSMTP relay serviceを使ってメールを送信する方法を記載します。SMTPプロトコルを使ってメールを送信するのはそれほど難しくありませんが、Google WorkspaceでSMTP relay serviceを設定するのと、メールを送信する際に使用するGoogle Accountの設定に幾つか分かり難い部分があったので、そこを中心に記載します。

前提

この記事では、以下の事柄を前提とします:

Google AdminでSMTP relay serviceを設定する

まず最初に、こちらのヘルプページに従って、Google AdminにてSMTP relay serviceを追加します。

SMTP relay serviceを追加

各々の項目の説明は、上記のヘルプページを参考にしてください。ここでは、Google Workspaceのライセンスが付与されたGoogle Accountを使ってメールを送信するので、”Allowed senders”はOnly registered Apps users in the domainsにします。

Cloud NATが持つ固定の外部IPからSMTP relay serviceに接続するので、この外部IP以外はSMTP relay serviceに接続できないようにします。”Authentication”のOnly accept mail from the specified IP addressesを有効にし、Cloud NATが持つ固定のIPを設定します。更にGoogle Accountのアカウント認証を使用してメールを送りたいので、Require SMTP Authenticationを有効にします。

最後に、Google Accountのアカウント認証の際のパスワードのやり取りを暗号化するために、Require TLS encryptionを有効にしてTLSを必須にします。

STMP relay serviceから送信されたメールを保存する

先程のヘルプページに記載があるように、”包括的なメール ストレージの設定”を行うことが推奨されています。この設定を行うことで、メールを送信した際に、そのメールの内容がメールの送信に使ったGoogle Accountのメールボックスの送信済みのところに保存されるようになるようです。

あんまりこの設定が何をするものなのか、上記の内容以上は分かっていないのですが、メールが正しく送信されたか確認するには便利なので、私は有効にしています。当然、保存できるメールの容量には制限があるので、それには注意してください。

メールの送信に使用するGoogle Accountの用意

メールの送信を送る際に使用するGoogle Accountを用意します。面倒なのが、SMTP relay serviceに対して認証を行う際には、このGoogle Accountに対して発行したApp Passwordsが必要になるところです。これは、SMTPプロトコルの中で二段階認証によってユーザ認証を行うことができないからです。

App Passwordsは、Google Accountのページから作成します。更にややこしいのが、普通にGoogle Accountを作成しただけではこのApp Passwordsを作成する選択肢は現れません。二段階認証を有効にすると、ようやくApp Passwordsを作成する選択肢が現れます。そもそも二段階認証ができない場合の認証の方法としてApp Passwordsを使用するのにも関わらず、まず二段階認証を有効にしなければApp Passwordsが作成できません。なんともややこしいです。

App Passwordsの作成の際は、”Select app”のところでMailを選択する必要がありました。他のものでもなんでも良いと思ってOtherで試していたのですが、認証が通りませんでした。まさかこの値が認証に影響しているとは思わなかったので、これで相当時間が掛かりました。

上記に気をつけながら、メールの送信を送る際に使用するGoogle Accountを作成し、二段階認証を有効にし、最後にApp Passwordsを作成します。

これで実際にメールを送信するのに必要な準備は整いました。

実際にメールを送信する

それでは実際にメールを送信してみましょう。こちらのレポジトリのサンプルのコードを参照してください。

package main

import (
	"crypto/tls"
	"fmt"
	"log"
	"net/smtp"
	"os"

	"github.com/atsuya/google-workspace-smtp-relay/auth"
)

func main() {
	smtphost := "smtp-relay.gmail.com"
	smtpport := 587
	hellohost := ""
	username := ""
	password := os.Args[1]
	from := ""
	to := ""
	subject := ""
	body := ""

	smtpserver := fmt.Sprintf("%s:%d", smtphost, smtpport)
	client, err := smtp.Dial(smtpserver)
	if err != nil {
		log.Panic(err)
	}

	if err = client.Hello(hellohost); err != nil {
		log.Panic(err)
	}

	tlsconfig := &tls.Config{
		ServerName:         smtphost,
		InsecureSkipVerify: false,
		MinVersion:         tls.VersionTLS13,
	}
	client.StartTLS(tlsconfig)

	authlogin := auth.AuthLogin(username, password)
	if err = client.Auth(authlogin); err != nil {
		log.Panic(err)
	}

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

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

	writer, err := client.Data()
	if err != nil {
		log.Panic(err)
	}

	data := fmt.Sprintf("To: %s\r\nSubject: %s\r\n\r\n%s", to, subject, body)
	_, err = writer.Write([]byte(data))
	if err != nil {
		log.Panic(err)
	}

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

	client.Quit()
}

パスワードを扱うため、smtpのライブラリも信用に足るものを使用しましょう。goは標準ライブラリとしてsmtpのクライアントを含んでおり、標準ライブラリであればある程度コードレビューもされているであろう想定から、goの標準ライブラリをそのまま使用しています。

以下が上記のコードの一連の流れです:

main関数の最初の方にある変数を埋めて (パスワードだけはコマンドラインのパラメータとして渡すことを想定にしています)、go buildでコンパイルします。コンパイルされた実行体をGCPのvmにgcloud compute scpでコピーします。コピーした実行体を実行し、メールが送信されたことを確認します。

結論

GCPは、メールを送信するサービスを提供していません。SendGridなどのサービスを使用することもできますが、Google Workspaceのライセンスを持っている場合は、Google WorkspaceのSMTP relay serviceを使用してメールを送信することができます。

送信できるメールの数に上限がありますが、そんなに頻繁にメールを送信する必要がないものには活用できるかと思います。

参照