同一アドレスに複数の同一メール送ろうとしてませんか？

# いきさつ
Aさん「katahiroさんに作ってもらったツール、設定されてるメールアドレスにメールが飛ぶはずだけど、今日のは届かないです」
katahiro「？？確認してみますね」

こちらの記事の流れに近いですが、また別の話です。

https://qiita.com/katahiro/items/881bd52163d1f4c7c43c

# 原因調査
組織に提供しているツールは`Slack`でBotとして機能しますが、以下のような流れで動きます
1. Slackの[ワークフロー](https://slack.com/intl/ja-jp/features/workflow-automation)が起票されて、特定の情報がチャンネルに書き込まれる
1. ワークフローの書込みをBotが検知して、書き込まれた内容を取得
1. 書き込まれた情報に対して採番を行い、以降の書込みを管理
1. 採番が完了した後に、設定されているメールアドレスに対して起票された内容を `Sendgrid`のメール配信にて周知
1. 以後書き込まれたメッセージでCloseの指示があれば、起票内容がCloseしたことをメール配信にて周知

というわけで、`Sendgrid`のメール送信で問題が発生したはず、と判断してログを確認。

# Sendgridからエラー応答されてる

```json:error log
{
  errors: [
    {
      message: 'Each email address in the personalization block should be unique between to, cc, and bcc. We found the first duplicate instance of [宛先が重複したメールアドレス] in the personalizations.0.to field.',
      field: 'personalizations.0',
      help: 'http://sendgrid.com/docs/API_Reference/Web_API_v3/Mail/errors.html#message.recipient-errors'
    }
  ]
}
```
宛先に設定されてるメールアドレスが重複してるよ、とエラーが出てました。

- 宛先重複したらエラーになるんだ
- そもそもなんで宛先重複したんだろ？

# Sendgridでは同一宛先が複数含まれていた場合エラー
メールの重複制約は実装したような、と思いきや想定外の入力がありました。
登録されたメールアドレスの一覧を出したところ、以下のような感じの部分が...
- `katahiro@ドメイン.com`
- `Katahiro@ドメイン.com`

ぁ、先頭だけ大文字になっとる。。。
そうです、メールアドレスって作成する時に大文字入れて作ったりすることもありますが、小文字にしても基本的には届くんですよね。
でも文字列としては別なので、メールアドレスの重複チェックが十分ではなく、異なる宛先として登録できてしまった。ということになります。

とりあえず配信できない状況は問題なので、なるべく簡易な実装の変更で以下のように書きました。
```javascript
const emailToList = [];
const emailList = emailClient.getList();
emailList.forEach(info => {
  emailToList.push(info.userEmail.toLowerCase());
});
const uniqEmailToList = Array.from(new Set(emailToList));
```
宛先設定の配列をまず作成して、メールアドレスを全て小文字に変換して突っ込み、別の配列に `new Set`で入れなおすと重複を排除してくれます。
これで無事にメール送信が実現できました。

# blastengineでは同一複数宛先でも送信可能
`blastengine`では以下のような設定を `bulk`に行ったところ、2通のメールが届きました
```javascript
const bulk = new Bulk;
bulk
  .setFrom('送信元メールアドレス', 'Admin')
  .setSubject('メールの件名')
  .setText('メールの本文')
  .addTo('katahiro@ドメイン.com') // 先頭小文字
  .addTo('Katahiro@ドメイン.com'); // 先頭大文字
```
ただ、blastengineの配信ログを見てると `katahiro@ドメイン.com`と先頭小文字の宛先で2件のログが表示されていたので、blastengineとしては配信先のメールアドレスは小文字変換されて管理している模様です。

# なぜ重複したメールアドレスが登録されるような事態になったのか？
ツールの思想としては、組織で使っているSlackで動くのでメール配信の宛先を追加、削除といった管理をするときに、以下のようなDMをBotに送る仕様としていました。
- `email add @slackユーザー`
- `email del @slackユーザー`

こうすると組織のSlackのユーザーは会社のメールアドレスと紐づけられているので、Slackのユーザー情報からメールアドレスを取得して、それを配信先として管理できると期待していました。

ただ、このツールの宛先は結構多くて個別にユーザー登録するのは面倒になるから、グループメールアドレスに送信してほしいということになり、以下の機能を追加しました。
- `email add メールアドレス`
- `email del メールアドレス`

これで、指定した特定のメールアドレスにも配信できるようになりました。めでたしめでたし。

ところが、グループメールアドレスを管理しているメールサーバーが不調で、運用している人が一時的にメールアドレスを全て個別登録したみたい。
これだけだと重複する理由にならないのですが、元々グループアドレスには含まれていないけれど宛先設定でSlackのユーザーで登録されてた人が、途中からグループアドレスに含まれるようになったみたい。
Slackで取得できるメールアドレスはSlackの仕様に沿って、`全て小文字のメールアドレス`が登録される。一方、グループアドレスに含まれるメールアドレスは申請のあったメールアドレス名で登録されているので、`大文字小文字関係ないメールアドレス`が登録される。
結果、小文字だけのメールアドレスと、大文字含むメールアドレスが登録されてしまい、今回の事象が発生した、ということがわかりました。

面倒ですね。。。

ロジックも改修したし、後日メールサーバーも復調して個別設定は消され、またグループアドレスに送信するようになり問題は解消しましたが、ユーザーのメールアドレス管理って面倒な部分があるのだな、と思いました。

# さいごに
いかがでしたでしょうか？
何気なしにユーザーが入力したメールアドレスでユーザー登録をしてしまうと、実は重複している可能性がある、という経験を共有させて頂きました。
特にメール配信に利用しているツール次第では、そこが動作したり、動作しなかったりが異なります。
アドレス管理の実態と、利用しているメール配信の仕組みがうまく合致しているか、ぜひ再確認する機会となれば幸いです。