【AWS-SES】C#でメール一括送付するツールを作成してみた

# 概要

以前にGASでQRCodeを一括でメール送付する仕組みを作成しました。これはこれで便利なのですが１日に送信できるメールが限られているのが弱点でした。そこで今回は社内でAWSをお試しで使っているので、SESを使ってメールを一括送付する仕組みを作成しました。

[■GoogleSpread（GAS）でQRCodeを一括で送付する](
https://qiita.com/tamoco/items/bb62ef68b6b5e34638b8)

# 構成
主にC#のフォームで作成しました。C#でのSESの利用についてはSDKを使う方法とSMTPを使用した方法がサンプルとしてあるので、今回はSMTPを使用する方法を採用しました。C#のフォームアプリでSMTPインターフェイスからEメールを送信する仕組みを作成します。フォームアプリについてはSMTPの設定値や送信アドレスなどを設定できるようにし、SESの設定ができていればアプリから一括でメール送信が可能です。

[■AWS SDK for .NETを使用してEメールを送信する](
https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/send-using-sdk-net.html)

[■C#でSMTPを使用してEメールを送信する](
https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/send-using-smtp-net.html)

# まずは Amazon SES の設定
送信するだけなら結構シンプルに設定できます。今回は送付用アドレスにGmailのメールを使用しました。ちなみに外部へのメール送信についてはサンドボックスの外への移動する必要があります。

いきなりイミワカメで困りますが、何もしていないと不正使用や悪用を防止し、送信者としての評判を保つため、新しい Amazon SES アカウントには一定の制限が適用されている状態になっています。それらの制限の解除をサポートセンターにお願いして解除してもらいます。SESの設定については以下に記載します。


# AWS-SESの設定方法
このツールを使用するにあたり、AWS側の設定が必要になります。要はAWS-SESで送信用のメールアドレスやSMTPの設定などを行います。以降の手順の参考としてスクリーンショットを取得しました。ただし画像の一部にモザイクなどの加工する部分がありますのでご了承ください。

## 【AWS-SES】マネジメントコンソールを開く
まずはAWSマネジメントコンソールを開きSESと入力してSimple Email Serviceの画面を開きます。

![2019-11-11 08_38_41-スタート.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412322/5d72062b-482e-fa6c-ad2e-fd7c6ccfc031.png)

## 【AWS-SES】送信用のアドレスを設定する
まずは送信用のメールアドレスを設定します。こちらに設定するメールアドレスは基本的には何でも大丈夫なはずです。メールアドレスを設定すると設定したメールアドレスにAWSから認証のメールが届きます。AWSからメールを承認（Verify）することで送信用のメールアドレスとして設定できます。

![sending_mail_setting.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412322/a603ee39-9fca-22f2-1671-edbcf6f1a680.png)

■ 設定したメールアドレスはC#フォームアプリの「送信アドレス」に設定します

## 【AWS-SES】サンドボックスの外への移動
SESの画面からSending Statisticsの画面を開きます。

SESはデフォルトだとサンドボックスと呼ばれる試用環境？の状態で制限が掛かっています。以下のスクリーンショットのように「Request a Sending Limit increase」と表示されている場合は、まだサンドボックスの状態で外部へのメール送信ができません。表示されている「Request a Sending Limit increase」をクリックしてサポートセンターへのページに遷移しサンドボックスの制限解除を依頼します。

ここで個人的に詰まったのがオレゴン以外のリージョンだといくら待っても制限が解除されませんでした。オレゴンのリージョンに選択しなおし制限解除の依頼をするとすぐに対応してくれました。まだ、アジアのリージョンもそこまで用意されていないのでオレゴンを選択した方がイイかもしれません。

なお、サンドボックスの制限解除はリージョンごとに設定する必要があるため、他のリージョンに切り替えているとRequest a Sending Limit increase」のボタンが表示されます。

![sending_limit.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412322/dc6d9f62-3fcb-7c47-f299-62b492675be8.png)
※リージョンをムンバイに切り替えてスクリーンショットを取得


## 【AWS-SES】SMTPの設定

最後にSMTPの設定を行います。SMTPの「Server Name」などは同じ設定だと思うので、サンプルのコードと同じであることを確認してください。確認後「Create My SMTP Credentials」をクリックするとIAMの画面に切り替わります。

![smtp_settings.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412322/b988a303-dab6-5963-5a31-2bd511fdbf6e.png)


IAMの画面に切り替わりIAMのユーザーを作成します。
SMTPでメールを送付する場合はIAM Userにメール送付用の専用のユーザーを作成します。

![smtp_setting_iam.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412322/962ebb08-d277-c6ab-2c18-b516a89632a2.png)


作成されると以下のような「認証情報のダウンロード」ボタンからSMTP USERとSMTP PASSWORDが記載されたCSVをダウンロードできます。

もしこの画面を閉じてしまってもIAMにはユーザーが登録されており、そのユーザーの認証情報から発行し直すことができます。

最悪、もう一度「Create My SMTP Credentials」で作り直しても大丈夫です。作り直した場合はIAMで必要のないIAMのユーザーは整理しましょう。


![2019-11-11 22_14_45-IAM Management Console.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412322/95169018-768c-688d-3fd4-044e447ab141.png)


■ ダウンロードしたCSVの情報を元にC#フォームアプリの「SMTP_USERNAME」と「SMTP_PASSWORD」を設定します

IAMの画面では先ほど作成したSMTPのユーザーが表示されているはずです。実は認証情報のアクセスキーがSMTPのユーザーに該当します。ここではパスワードを確認することができません。ただしアクセスキーを発行し直しSMTPのユーザーとパスワードを取得しなおすことはできそうです。

![2019-11-11 22_08_31-IAM Management Console.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412322/f4c2d05a-4e3d-303d-ad5b-6c17509195db.png)


# C#によるフォームアプリの作成
上記のAWS-SESが完了したらC#フォームで送る準備をします。ツールを使う場合は上記のSMTPユーザーなどを設定すれば一括でメールを送付することができます。
なおAWSの設定情報のどの項目を設定すべきかはAWS手順の画像の下に■の記号で補足している部分を参考にしていただけると助かります。
それでは実装した機能を記載していこうと思います。

## 【C#フォーム】プロパティによる設定値の保存
入力した設定値についてはプロパティに保存され次回起動したときにも設定値を維持するようにします。
保存する値がセキュアなモノである場合は、暗号化して保存するようにしています。

これは以前にプロパティではなくリソースを使っていたときにEXEのバイナリから読み取れてしまうことがあったので、念のために暗号化の処理を挟むことにしました。

## 【C#フォーム】Excelから送付リストの取り込み
DataGridViewに表示する内容についてはExcelファイルから取り込めるようにしました。外部のデータベースに接続して利用することも可能ですが、データベース自体が決まっていないので、とりあえずClosedXMLを使用してExcelファイルを読み込むようにしました。

ClosedXMLを使用すればExcelがインストールされてなくても処理できるので便利ですね。Office Interopでも読み込めますが後処理とかちゃんとしないとイケないんで少し面倒です。
![フォーム 送信画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412322/8fdd11e3-5734-674d-4e0a-b4912d61fc62.png)


取り込んだ後のDataGridViewでは列項目で絞り込めるようにしています。
![フォーム 送信画面 絞り込み.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412322/c718851d-5b44-95e7-6fc1-38cbca9a773f.png)


## 【C#フォーム】テキストの置換
３つの項目だけですが自分で設定したテキストの内容と取り込んだExcelファイルの列項目に対応して置換するようにしました。文章にするとわかりづらいため設定画面も日本語でわかりやすくしてみたつもりです。
![フォーム取り込みデータの設定.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412322/e52e5fec-6772-55ee-9552-ad2126705bd5.png)

## 【C#フォーム】AWSの設定
AWSで設定したSMTPなどを設定できます。AWS側の設定については後段で説明します。
![フォーム AWS-SESの設定.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412322/02ddc8e0-5566-4c98-e311-4807c50615b4.png)

## 【C#フォーム】メールの設定
メールの件名や本文の設定ができます。上記のテキストの置換に合わせて本文を置換することができます。
![フォーム メールの設定.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412322/5c4bcbe0-2971-ad5b-ed86-9d2ad097b926.png)

## 【C#フォーム】ログ出力
送信後に本当に送信されたかどうか不安だと思うのでログを出力するようにしました。


## 送信結果
捨てメアド【メルアドぽいぽい】というサービスでメールアドレスを作成して試しに送ってみました。

![2019-11-11 07_13_10-捨てメアド【メルアドぽいぽい】.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412322/c8d9bc02-e282-519d-bcb5-7218e55940bf.png)

テキストの置換も上手く機能しています。

![04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412322/11788745-e9f8-90b2-de20-b2699683cfad.png)

リンク先を確認するとちゃんと社員番号のQRコードが生成されています。
![2019-11-11 22_51_08-QRCode　ツクール.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412322/ace4aab1-d66e-031b-9532-1a14a01026b2.png)



# 総評
AWS-SESとC#のフォームアプリで一括で送付する仕組みができました。別にメールで送付するならGASでもイイじゃんとなりそうですが、GASはGASで送付エラーのときが若干怖かったりします。
作成したC#のフォームアプリでは送付後にログも出力するので正しく送付されたかどうか確認できます。もし送付できていなかった場合でもログから拾うことができ、もう一度再送してあげることもできます。
今回、作成したC#フォームアプリは以下の場所に格納しましたのでAWS-SESの設定をした上でご試用いただければ幸いです。


[■AWS-SendMail.zip（BOXの共有URLです）](https://app.box.com/s/vyrg19hy1im8fum1bg9cxxkqj1jm25dq)