コネヒト開発者ブログ

コネヒト開発者ブログ

TravisCIの料金体系の変更によるmacOSでのビルドへの影響(有料ユーザー向け)

2020/11/02からTravis CIの料金体系が変わりました。 blog.travis-ci.com

影響があるのは以下の4つ場合です。

  • Building on the macOS environment
  • Building with more than 10 concurrent builds
  • Building on a Trial Plan
  • Building on a public repositories only

コネヒトでは月額$249(5 concurrent job)のplanでweb, iOS, Androidで使っています。

このエントリーでは、コネヒトで影響のあった Building on the macOS environment についてのみふれていきます。

(注:TravisCIを無料でpublic repositoryでのみmacOSでビルドするのに使われている方には参考にならないです🙇🏻‍♂️)

macOS環境でのビルドへの影響

Travis CIではこれまではOSに関係なく同じプラン内で使えていましたが、今後はmacOSの場合はビルド時間に応じて追加料金が必要となります。 料金は以下の通りです。

  • $15で25000 creditを購入
  • macOSだと1分で50 credit

CircleCIとそろえているようでした。

いつから?

現在のプランの有効期限が切れると次回から新しいプランに移行するようでした。

Beginning on Monday the 2nd of November 2020, customers impacted by pricing changes listed above will be gradually upgraded to the new pricing scheme upon their plan expiration date.

他のCIとのコストの比較

追加料金必要になるなら他のCIに乗り換えることも検討するかと思いますのでコストを比較してみました。

月にどれくらい使うか、チームの規模、iOS以外の開発での利用などによって最適なものは異なってくるのでどれが一番良いとは一概に言えません。

ビルド時間 Travis CI Circle CI bitrise GitHub Actions
2000min $60 + $69/$129/$249 ※1 $60+$15 ※2 $100/$300 ※3 $136
2500min $75 + $69/$129/$249 ※1 $75+$15 ※2 $100/$300 ※3 $176
3000min $90 + $69/$129/$249 ※1 $90+$15 ※2 $100/$300 ※3 $216
3500min $105 + $69/$129/$249 ※1 $105+$15 ※2 $100/$300 ※3 $256

※1 Travis CIはconcurrent planによってベースの料金が異なります

※2 Circle CIはユーザー数によって料金が異なります

※3 bitriseはプランによって料金が異なります

2020/11/11時点の情報です。

コネヒトでの今後の方針

コネヒトのiOS開発でのCIの利用状況は月に3000分くらいで、コスト的には他のCIと遜色なさそうでした。

ただTravis CIを使っている上で ログが最大4MBまでしか保存されない というところが結構不便に感じていたので、同じくらいのコストで定額で使えるbitriseに乗り換えようかと検討しています。

potatotips #71 で Mixpanel について LT してきたのでその補足や失敗談の共有

こんにちは!コネヒトでアプリケーションエンジニアをしているaboです。

先日開催された potatotips #71 iOS/Android 開発 Tips 共有会で、コネヒトでも活用しているプロダクト分析ツールの Mixpanel について話してきました。コネヒトでは、エンジニアもプロダクトをより良くする開発チームの一員として仮説検証や施策を考えるために Mixpanel や Redash などの分析ツールを触ります。Mixpanel は GUI で比較的かんたんに分析できたり、レポートのビジュアライズが強力で、コネヒトでも分析ツールのひとつとして役立っています。

potatotips.connpass.com

今回は、発表内容の補足や失敗談の共有をします。当日の発表資料はこちらです。

GUI でかんたんに分析できる

発表で出さなかった例として、「Compare to previous year」を選択すると、前年の値と比べられたり(点線が前年、実線が今年)

f:id:aboy_perry:20201028160221p:plain
前年との比較

Annotation という、レポートの日付に注釈をつけられる機能があったりします。下の画像の例だと、機械学習のモデルを更新したんだな、ということがレポート上でわかりやすくなります。

f:id:aboy_perry:20201028184839p:plain
Annotation をつけてやった施策をわかりやすくする

ユーザーの Activity Feed をエラー調査に活用する

ユーザーの行動を時系列で確認できる Activity Feed も便利です。実際にアプリケーションのエラーを調査するときに、Activity Feed で該当のエラーが発生した時刻の前後の行動をみたりします。そして「通常のユースケースで起きてそう」「いや何か変だぞ」みたいなコミュニケーションをしたりしています。

f:id:aboy_perry:20201028181426p:plain
ユーザーの行動を時系列で確認できる Activity Feed

Cohorts も便利

発表では触れられませんでしたが、Cohorts というユーザーをグループ化できる機能があります。つくった Cohorts は分析の条件に入れたり、ユーザーリストを CSV としてエクスポートできたりして便利です。例えば「過去7日間に10回以上起動した Android ユーザー」などです。

f:id:aboy_perry:20201028170603p:plain
Cohorts の作成画面

エンタープライズプランであれば Cohorts はファネル分析やリテンション分析のレポートからも作成できます。ファネルであれば「施策で追加したバナーから購読画面を開いたが購読せず離脱したユーザー」や「ディープリンクから投稿画面を開いてそのまま投稿してくれたユーザー」など。リテンションであれば「投稿した次の日に起動しなかったユーザー」のようなユーザーのリストを、レポートからポチポチするだけで作成できます。

f:id:aboy_perry:20201028164022p:plain
ファネル分析のレポート上で選択するだけで Cohorts がつくれる

コネヒトでは使っていませんが、Cohorts に対してメッセージを送ることもできます。

help.mixpanel.com

MTU が想定以上に増えた

最後に失敗談です。Mixpanel は MTU (Monthly Tracked User) という方法で費用が計算されます。 MTU は対象の月にイベントを実行したユーザー数のことで、Mixpanel では distinct_id という識別子でユーザーが一意に決定されます。

コネヒトではアプリ (Native と WebView) からのみ Mixpanel にイベントを送信しており、distinct_id にはママリのユーザー ID が設定されるようになっていました。なので MTU はアプリ版ママリの月間ユニークユーザー数と近しい値になっていました。

しかし新たに Mixpanel へのトラッキングを追加した際、ママリにログインしていなくても見ることができるブラウザも対象にしました。すると distinct_id には Mixpanel で生成されたユニークな ID が設定されたことによってそれぞれが別のユーザーとしてカウントされてしまい MTU が想定以上に増えてしまいました。

f:id:aboy_perry:20201027231719p:plain
MTU が爆増した2週間

このときは、(1)コスト増のインパクトが大きいこと(2)トラッキングの目的であったデータ分析が終わっていたため消しても問題ない、という理由から該当のコミットをリバートする対応をしました。

公式ドキュメントには、集計対象外のイベントや MTU の計算方法の例外、MTU に大きな影響を与えているイベントの調べ方なども書かれてあります。

help.mixpanel.com

おわりに

LT で話せなかったことや、失敗談を共有しました。プロダクト分析ツール選びの際に参考のひとつになれば幸いです!


コネヒトではプロダクトを一緒に成長させられるエンジニアを絶賛募集中ですので、まずはお話だけでも聞きにきてください!

hrmos.co

コネヒトマルシェオンライン「事業を支えるWeb開発」vol.2 を開催しました!

こんにちは! @otukutun です。

先日 2020/09/25(金)に コネヒトマルシェオンライン「事業を支えるWeb開発」vol.2 をランサーズさんと共同開催で開催しました!コネヒトマルシェはみんなの「知りたい」「知ってる」をおすそ分け!をコンセプトにした参加者が主役の勉強会です。今回はオンライン開催になってから第二回目になります。前回はBASEさんとこんな内容でやっておりますのでそちらもよかったらご覧ください。

発表内容

今回はオンラインになってから第二回の開催となりますが、テーマは第一回に引き続き「事業を支えるWeb開発」というテーマでお送りしました。今回の発表内容は以下のようになっています。ではさっそく、これからLTの内容など簡単にご紹介できればと思います。

  • @奥津(コネヒト株式会社所属) Fabricate導入した話
  • @金澤さん(ランサーズ株式会社所属)ランサーズのCakePHP4移行について
  • @富田さん(コネヒト株式会社所属)コネヒトの健全性を支える GitHub Actions の事例紹介
  • @安達さん(ランサーズ株式会社所属)ECS/Fargateの活用事例 ( CakePHP編)
  • @山田さん(コネヒト株式会社所属)ページネーションから考えるSQLパフォーマンス

Fabricate導入した話 / @奥津(コネヒト株式会社所属)

こちら私が発表した内容になります。CakePHPにおけるテストデータ生成からFabricateというテストデータ生成ツールを導入した内容の発表でした。年数が経っているプロジェクトで既存のFixtureとFabricateを共存させて使っていく話をしました。

ランサーズのCakePHP4移行について / @金澤さん(ランサーズ株式会社所属)

既存のプロジェクトを分割しながらCakePHP4に移行していく発表でした。CakePHP4移行に当たってのレポジトリ戦略から始まり、アップデートしてくなかで多数のOSSにコントリビュータされていていて、とても刺激を受けた発表でした。弊社でメンテナンスしているcakephp-master-replicaにもコントリビュートしていただいてきました。

コネヒトの健全性を支える GitHub Actions の事例紹介 / @富田さん(コネヒト株式会社所属)

開発における健全性の定義から始まり、それをGitHub Actionsを使って観測・改善していこうという発表でした。ツールの導入して日が浅いようなので今後の経過も気になりますね!

ECS/Fargateの活用事例 ( CakePHP編) / @安達さん(ランサーズ株式会社所属)

こちらはCakePHPの開発環境を作るお話からはじまり、stg・本番環境をECS Fargateに移行する話を中心に発表していただきました。ログまわりの集約方法の話や作業用コンテナを設置している話とても共感しながら聞いておりました。Fargateはデバッグしづらいというのはその通りでうなづいちゃいました。

ページネーションから考えるSQLパフォーマンス / @山田さん(コネヒト株式会社所属)

先日業務で実装されたページネーションから、SQLパフォーマンスを考えてどんなindexを貼るべきかという発表内容でした。個人的にindexまわりの話は好物なので楽しく聞くことができました。MySQLのサンプルデータは気軽に試してみるのによさそうだな〜と思いました。

最後に

ランサーズさん、コネヒト社共にメインで使っているCakePHPの発表だけでなく、GitHub ActionsやSQLなどいろんなテーマの発表がありとても興味深い勉強会になったと思っています。

またまた第三回も開催したいと思いますので参加される方ははたまた共同開催していただける会社さんも募集しておりますのでぜひよろしくお願いします!

ということで、また会いましょー!

コピペでできるGitHub Actionsでreleaseブランチのマージ、リリースノートの作成の自動化【git-flow用】

こんにちは、コネヒトでiOSエンジニアをやっていますyanamuraです。

iOSやAndroidアプリの開発だとgit-flowを使って開発することも割と多いのではないかと思います。 git-flowの場合releaseブランチをマージする場合はdevelopとmain/masterにマージする必要があるのでちょっと手間がかかります。 また、main/masterにマージ後にタグをつけてpushし、さらにリリースノートを書いたりすると結構面倒です。

これをGitHub Actionsで自動化しました。

想定しているフロー

以下の手順は手作業で行います

  1. release-x.x.x という命名ルールでreleaseブランチをつくる
  2. 1のreleaseブランチでPull Requestを作成する。
  3. 2のPull Requestのbodyにリリースノートに書く内容を記載する
  4. releaseブランチをマージしたいときは、Pull Requestにshipit ラベルをつける

こうすると自動でマージが行われ、vx.x.x というタグがつけられ、Pull Requestのbodyに書いた内容がリリースノートに反映されます。

GitHub Actionsの作成

.github/workflows というフォルダを作成し、その中にymlファイルを作成し、以下の内容をコピペするだけです。

name: automerge
on:
  pull_request:
    types: [labeled]
jobs:
  automerge:
    if: github.event.label.name == 'shipit'
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: Extract branch name
      uses: mdecoleman/pr-branch-name@1.0.0
      id: extract_branch
      with:
        repo-token: ${{ secrets.GITHUB_TOKEN }}
    - name: Extract tag name
      shell: bash
      run: |
        branch=${{ steps.extract_branch.outputs.branch }}
        echo "##[set-output name=tag;]$(echo ${branch#release-})"
      id: extract_tag
    - name: Merge
      if: startsWith(steps.extract_branch.outputs.branch, 'release')
      uses: yanamura/git-flow-merge-action@v1
      with:
        github_token: ${{ secrets.GITHUB_TOKEN }}
        branch: ${{ steps.extract_branch.outputs.branch }}
        tag: v${{ steps.extract_tag.outputs.tag }}
    - name: Get body from PullRequest
      id: pr-body
      uses: actions/github-script@v2
      with:
        github-token: ${{secrets.GITHUB_TOKEN}}
        result-encoding: string
        script: |
          const result = await github.pulls.get({
            owner: context.repo.owner,
            repo: context.repo.repo,
            pull_number: context.issue.number
          })
          return result.data.body
    - name: Create ReleaseNote
      if: startsWith(steps.extract_branch.outputs.branch, 'release')
      uses: actions/create-release@v1
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      with:
        tag_name: v${{ steps.extract_tag.outputs.tag }}
        release_name: Release ${{ steps.extract_tag.outputs.tag }}
        body: |
          ${{ steps.pr-body.outputs.result }}
        draft: false
        prerelease: false

マージする際のトリガーとなるラベル名やリリースブランチの命名、タグの命名など変えたい場合はカスタマイズしてみてください。(masterではなくmainブランチの場合は、こちらを見てmainを指定してください)

かんたんにできると思いますので、ぜひお試しください!

今回ご紹介したところ以外にもGitHub Actionsを活用して自動化を行っているのでまた別の機会にご紹介できたらなと思います。

最後に

コネヒトではエンジニアを募集しています。少しでもご興味のあるかたはぜひ一度話を聞きに来てください! hrmos.co

hrmos.co

iOSDC Japan 2020 に協賛、参加しました!

こんばんは!コネヒトでアプリケーションエンジニアをしているaboです。

先日開催された iOSDC Japan 2020 は、前夜祭含め3日間におよび、大盛況のうちに幕を閉じました。今回はオンライン開催ということもあり、例年とは違った準備も必要で大変だったと思いますが、今年も素敵なコミュニティだったと思います。ニコ生での開催だったので、リアルタイムに視聴者のコメントが流れるのが楽しかったですし、事前録画の発表に対して発表者による補足コメントが流れるのも新鮮でした。また、Discord をつかった Ask the Speaker や雑談部屋などのチャレンジも印象的でした。

iOSDC Japan 2020 に関わった皆様に感謝致します! 🤝

f:id:aboy_perry:20200921183938j:plain

コネヒトは iOSDC Japan 2020 に協賛させていただきました

今年もシルバースポンサー、Tシャツスポンサーの2つで協賛させていただきました!

iOSDC は昨年も協賛させていただきましたが、根底にあるのはコネヒトが掲げる「人の生活になくてはならないものをつくる」というミッションです。エンジニア文脈においても、コネヒトが技術コミュニティになくてはならないような会社になるべく、様々なアウトプットを支援・促進するような制度*1も存在します。自分たちが普段お世話になっている技術コミュニティに、こうした形でサポートさせていただくことで、一緒に盛り上げていくことができたらと思っています。

f:id:aboy_perry:20200921173643j:plainf:id:aboy_perry:20200921173716j:plain

機械学習まわりの発表もいくつかありました

ぼくがちょうど機械学習をサービスに組み込んでいく動きをするチームに所属している*2のもあり、機械学習に関連する発表にも興味がありました。

とくに『機械学習のブルーオーシャン、CoreML』という発表に関しては、個人的にも Core ML を少し調べていたのもあり、実案件レベルをこなしている方の目線から見る Core ML を知る貴重な機会でした。

発表を聞いてみると、実務レベルでは Core ML モデルをつくる部分も含めて全体を触る必要があり、そのなかで機械学習やグラフ可視化ツール、Core ML Tools、Swift、Python などの知識が求められるため、ブルーオーシャンといえど幅広い知識が必要になりそうだなーと感じました。このあたりは全て独学だと骨が折れそうな感じですが、コネヒトには機械学習エンジニアがいるので、チームで取り組めればラクそう...!

Core ML はコネヒトでも可能性がなくはない技術なので、今回の発表が聞けたのはとても有意義でした!

最後まで大盛り上がりで終了!

2日目の LT タイムには視聴数が2000人を突破し、その後のクロージングでは2500人ほどになっていました!LT は事前録画ではなくリアルタイムで行われたので、オフラインで開催された昨年までと同様ライブ感のある盛り上がりでした。

f:id:aboy_perry:20200921182021p:plain
クロージングの様子

というわけで簡単ではありますが参加ブログとさせていただきます!今年も最高のコミュニティでした!あらためて、iOSDC Japan 2020 に関わった皆様ありがとうございました!

コネヒトでネイティブアプリをグロースさせるために使っているSaaS

こんにちは!コネヒトでアプリケーションエンジニアをしているaboです。

今回はコネヒトで特にネイティブアプリをグロースさせるために使っているSaaSを、それぞれどう使っているかも合わせて紹介します。

今回紹介するのはこの4つで、ざっくりとした使い方は以下の通りです。

  • Firebase:クラッシュ分析や、A/B テストなど
  • KARTE:ポップアップ配信
  • Repro:プッシュ通知配信
  • Mixpanel:フローやファネル、リテンションなど多様なデータ分析

それぞれについてもう少し詳しく紹介していきます。

f:id:aboy_perry:20200911173902p:plain

Firebase のつかいかた

Firebase は多くの機能を持つアプリ開発プラットフォームですが、コネヒトでは以下の機能をつかっています。

  • Firebase Analytics:BigQuery とリンクさせて多様なデータ分析
  • Firebase Crashlytics:クラッシュ/非重大なイベント分析
  • Firebase App Distribution:テストアプリ配信
  • Firebase A/B Testing:A/B テストの実施
  • Firebase Remote Config:A/B テストなどのパラメータ配信
  • Firebase Performance Monitoring:パフォーマンス分析

Firebase Analytics

ネイティブアプリから Analytics へアプリの各種イベントを送っていますが、Analytics をそのまま使うというよりは、BigQuery 経由で活用されることが多いです。Firebase を BigQuery にリンクすることでサンプリングされていない元のイベントデータを見ることができ、溜まったデータは機械学習や、サービスの分析等につかわれます。コネヒトでは BigQuery をはじめとする各種データソースを Redash から参照可能にしており、かつ社員だれでも Redash にアクセスできます。これらは Query Results を含むデータソースとクエリを駆使して比較的難易度の高いデータの分析にも活用されています。

Firebase Crashlytics

アプリのクラッシュ情報がわかる重要な機能です。Fabric の deprecated に伴い移行しました。コネヒトではクラッシュ情報を流す Slack チャンネルを用意して、新規、または頻発しているクラッシュを検知できるようにしています。

f:id:aboy_perry:20200908173002p:plain
アプリのクラッシュログが流れるSlackチャンネル

Firebase App Distribution

iOS のテストアプリの配布に使っています(Android は DeployGate です)。こちらも Fabric から移行しました。コネヒトでは fastlane を使って App Distribution による配布を自動化しています。GitHub 上で develop ブランチが更新されたら自動で配布されるようにしています。

Firebase A/B Testing

ネイティブアプリ側のコード修正だけで完結する A/B テストを実施するときに使っています。A/B のグルーピングに関係するパラメータやイベントは Firebase だけでなく他のサービスにも送っているため、A/B テストの結果は他のサービスでも分析できます。コネヒトでは Firebase A/B Testing が出す結果だけを見て判断せず、他のサービスも併用することが多いです。

Firebase Remote Config

何かしらのデータをネイティブ側にハードコードしてしまうと、変更するためにはアプリのバージョンアップや審査が必要になり手続きや考えることが増えます。そのため PDCA をより早く回したい施策などは Remote Config を使うことがあります。定義したデータは iOS/Android で共通して使え、専用の API を用意する必要もないので便利です。

Firebase Performance Monitoring

アプリのパフォーマンスを分析できる機能ですが、コネヒトではまだ実験段階です。詳しくは Performance Monitoring を深掘りしたこちらの記事をご覧ください。

tech.connehito.com

KARTE と Repro のつかいわけ

KARTE は CX(顧客体験)プラットフォーム、Repro は CE(カスタマーエンゲージメント)プラットフォームです。両者とも多機能ですが、コネヒトではそれぞれの長所を生かしてポップアップとプッシュ通知の配信に使っています。

まず KARTE はポップアップの配信に使っています。特定の記事やページを見たユーザーを配信対象に設定できたり、配信しない曜日や時間帯を設定できる点が魅力です。

一方 Repro はプッシュ通知の配信に使っています。KARTE もプッシュ通知配信が可能ですが、負荷分散設定がなかったり、秒間や月の送信上限が現状のママリのプッシュ通知配信の要件に一部応えられないためです。

Mixpanel のつかいかた

最後に紹介する Mixpanel はグロースハックツールで、フローやファネル、リテンションなど様々な角度からの分析が可能です。また、GUI による分析作業のしやすさや、分析結果のビジュアライズによってエンジニア以外の職種も比較的簡単に扱える点が魅力です。

コネヒトではネイティブアプリ上で起こるイベントのほとんどは Mixpanel に送っていて、施策の効果検証や仮説探索のためのデータ分析などに役立っています。

f:id:aboy_perry:20200914225121p:plain
Mixpanel でつくれるダッシュボード

また、細かいですが今年の6月頃には Mixpanel のレポート URL が Slack 上でプレビュー表示されるようになり、ますます使いやすくなっています。この辺りの詳細は Mixpanel 公式の Slack / Mixpanel Integration で確認できます。

f:id:aboy_perry:20200911011240p:plain
Mixpanel のレポートが Slack でプレビューされるようになった

Profile Properties と Event Properties

Mixpanel を例にして、プロパティのつかいわけを紹介します。Mixpanel のプロパティのうち Profile Properties はユーザーに紐づくため、ユーザーの状態が変わるとプロパティの値も変わり、Mixpanel 上では常に最新の値を確認できます。一方 Event Properties はイベントに紐づくため、イベント発生時点での状態が記録され、あとから確認できます。

例えば検索イベントにおける検索クエリは、イベント固有なため Event Properties として設定しています。一方で、ユーザーの課金状態は Profile Properties と Event Properties 両方に設定しています。これは、あるイベント時点での値と、ユーザーの最新の値両方を確認したいニーズがあるからです。

また、課金状態のような、全てのイベントに対して共通して付与したいプロパティに関しては Super Properties が使えます。一度 Super Properties に追加するコードを書いてしまえば、イベントごとに個別の Event Properties として追加する必要がなく、忘れる心配もないのでとても便利です。

おわりに

コネヒトで特にネイティブアプリをグロースさせるために使っているSaaSを4つ紹介しました。このあたりの話は、何が正解ということもないので、この記事を読んでくださった皆さんの「ウチはこんな風にしてます!」というのをぜひ聞いてみたいです!


コネヒトではネイティブアプリを一緒に成長させられるエンジニアを絶賛募集中ですので、まずはお話だけでも聞きにきてください! hrmos.co

バウンスメールと AWS SES

こんにちは! フロントエンドエンジニアのもりやです。

先日エンジニアチーム内で AWS SES のバウンスレートについて話題になったのですが、その時に「バウンスって何?」という声がちらほら聞こえてきました。

Webサービスではユーザー登録や問い合わせなどメールが必要になる場面が多いです。 バウンスなどはメールを安定して送信するために必要な知識なのですが、なかなか担当する人以外は知られていないのかな、と思いました。 そこで今回は、バウンスメールなどのメール運用で知っておきたいエンジニア向けの知識を紹介しようと思います。 (執筆時に調べた資料などは最後に記載しておりますので、より詳しく知りたい方はそちらもあわせて読んでみてください)

また、コネヒトでも使用している AWS SES の場合、バウンスをどう扱っていく必要があるかについても紹介します。

(※なお SMTP などのメールの仕組みや仕様などは本記事では解説しません)

Webサービスとメール

LINE や Slack など様々なコミュニケーションサービスが普及している今でも、メールは欠かせないツールです。 理由としては、メールアドレスを知るだけで送信でき、安価に使えることだと思います。 そのため、アカウント登録やお知らせなど様々な場所で使われています。 (SMS も電話番号だけで送信できますが、送信単価がメールに比べると高いですね)

ところが、その便利さ故に困った事が出てきます。 ご存知スパムメールですね。 メールアドレスが知られてしまうだけで、スパムメールも送信されてしまいます。

日常的に大量のスパムメールが送信されてくれば、メールは使い物にならなくなってしまうでしょう。 しかしながら様々な対策が取られているおかげで、私達は日頃ちゃんとメールを使うことができています。

ところがこの「様々な対策」が時に我々サービス提供者にとってネックになってしまう場合があります。 ここからが本題です。

メールは送信元が評価されている

今回お伝えしたいことの本題はこれです。 メールは送信元が正しくメールを送信しているかを評価されています。 (ちなみに本ブログでは「評価」で記載を統一しますが「レピュテーション」とも呼ぶ場合も多いです)

評価しているのは特定の組織というわけではなく、メールサービスを提供しているISPなどが個別に評価しています。 なので、統一された評価基準が存在するわけではありませんが、評価を下げてしまうよく知られた要因はあります。 それを説明していきます。

評価が下がる主な要因

送信元の評価が下がる主な要因を紹介します。

SPF/DKIM が設定されていない

SPF/DKIM とは、メールの送信ドメインを認証するための仕組みです。 なりすましメールを防ぐことができます。

自分で「私は〇〇の者です」というだけ言う人と、身分証明書を合わせて提示してくれる人のどちらが信用できるか、といったイメージですかね。

SPFはIPアドレスを使って、認証をしています。 メールの送信元のIPアドレスと、DNS に設定されている SPF レコードが一致するかを検証します。

DKIM は電子署名を使って認証をしています。 秘密鍵で署名した情報をメッセージと共に送信し、DNS に設定されている公開鍵の情報を元に正当性を判断します。

どちらも DNS が絡んできます。

バウンスメールが多い

冒頭にも出てきたバウンスメールです。

バウンスメールとは、何らかの原因でメールが相手まで到達できなかったメールのことです。 バウンスメールには以下の2種類があります。

  • 一時的なエラーによるソフトバウンス(例:メールボックスの容量がいっぱいだったなど)
  • 恒久的なエラーによるハードバウンス(例:メールアドレスが存在しないなど)

本ブログに出てくるバウンスとは、後者のハードバウンスを指します。

なぜハードバウンスが多いと評価が下がるのかと言うと、適当なリストやランダムに生成したメールアドレスに送信している疑いがあるためです。 要はスパムを送る業者などに出る特徴ということなのでしょうね。 バウンスを検知した場合は、再送しない対策が必要になります。

AWS SES では、バウンス率を2%未満に保つことを推奨しています。 また、5%を超えると対応を求められ、最悪送信できなくなる場合があるようです。

最良の結果を得るには、バウンス率を 2% 未満に維持する必要があります。

バウンス率が 5% 以上になると、アカウントはレビュー対象になります。バウンス率が 10% 以上の場合は、高いバウンス率の原因となった問題が解決するまで、以後の E メール送信を一時停止することがあります。

Amazon SES Sending review process FAQs - Amazon Simple Email Service

苦情が多い

苦情とは、受信ユーザーが「このメールはスパムだ」と報告するやつです。 例えば Gmail には「迷惑メール」というボタンが設置されていますね。

AWS SES では、苦情率を0.1%未満に保つことを推奨しています。 また、0.1%を超えると対応を求められ、最悪送信できなくなる場合があるようです。

最良の結果を得るには、苦情率を 0.1% 未満に維持する必要があります。

苦情率が 0.1% 以上になると、アカウントはレビュー対象になります。苦情率が 0.5% 以上の場合は、高い苦情率の原因となった問題が解決するまで、以後の E メール送信を一時停止することがあります。

Amazon SES Sending review process FAQs - Amazon Simple Email Service

受信ユーザーが明示的に送るものなので、スパム判定の重要な指標になっていそうですね。

メールに「unsubscribe」リンクが設置されて、ワンクリックで購読解除できるようになっているサービスも多いですね。(特に海外のサービスに多い印象です) これはユーザビリティ以外に、購読解除を素早く行わせることで「迷惑メール」ボタンを押されないようにする、という理由もあるのではないかと思います。

AWS SES を使う場合の注意点

AWS SES は上記のようなバウンスや苦情を自動で管理・対応してくれません。 これらを監視・対応するのはAWS利用者の責任となっています。 そのため AWS SES を使う際には、最低でもバウンスや苦情を検知しておく必要があります。

(2020/09/20 追記)
アカウントレベルのサプレッションリストを使用すると対応もできるようです。 詳しくは「アカウントレベルのサプレッションリストを使用する」の章をご覧ください。

バウンスや苦情の検知方法

AWS SES でバウンスが起きた場合は、SNS Topic に送信することができるようになっています。 とりあえずバウンスと苦情に SNS Topic を登録し、メールでサブスクリプションを作成すればバウンスや苦情が発生した際に気づくことができます。

ses_sns.png

メールの場合はこのように配信されます。

sns_mail.png

配信件数が多くない場合は、メールで通知して対応するだけでも十分かもしれません。 ただし内容が JSON で送られてくるので読みにくくはありますが・・・。

たくさんのメールを配信するようになると、利用者のメールアドレスの打ち間違いなど、一定数のバウンスも発生してくるようになると思います。 そういった場合はシステム的に対応できるようにしておくほうが良さそうです。

なお CloudTrail では SendEmail などの API コールは記録されないようです。残念。

ses.png

Logging Amazon SES API calls with AWS CloudTrail - Amazon Simple Email Service

また AWS SES 以外のメールサービスにはバウンスに対応してくれるものもあるので、そちらも検討しても良いかも知れません。 例えば SendGrid にはバウンスに対応できる機能があるようです。 (私は使ったことがないので、具体的にどのようなものかは分かりません)

SendGridでは、ハードバウンスが発生した場合は、そのアドレスをサプレッションリストに登録します。サプレッションリストに登録されている宛先への送信リクエストがあった場合、SendGridはそのメッセージを破棄(Drop)し、受信者のサーバーへの送信処理を行いません。無効なアドレスに対し送信し続けることはレピュテーションを下げる原因となってしまうからです。

バウンスメールとその対策 | SendGridブログ

Tips: バウンスや苦情をテストする場合

バウンスなどのテストをする場合は、AWS から提示されているテスト用のアドレスを使いましょう。 これらのアドレスはバウンス率や苦情率にカウントされません。

Testing email sending in Amazon SES - Amazon Simple Email Service

AWS SES でバウンスなどをシステム的に対応する場合

基本的にやり方はAWS利用者に委ねられています。 バウンスや苦情は SNS Topic に対して通知することしか設定できないようなので、SNS から HTTP や Lambda のスブスクリプションを作ってその先で何らかの対応をする、という感じになるでしょう。

私自身、ここまで対応したことはなかったので、バウンスメールを捕捉してメール送信を制御するサンプル実装を作ってみました。

GitHub: hyiromori/example-ses-bounce

構成はこんな感じです。

example-ses-bounce.png

バウンスメールを検知した場合に DynamoDB に保存して、送信前にバウンスの履歴がないかをチェックするような仕組みになっています。 詳しく見たい方は README をご覧ください。

アカウントレベルのサプレッションリストを使用する(2020/09/20 追記)

ブコメで「アカウントレベルのサプレッションリストを使えばもっとシンプルになる」というコメントがありました。 情報ありがとうございます。

この機能は2019年11月にリリースされたようですね。

Amazon SES がアカウントレベルの抑制リストを発表

試してみましたが、上記のサンプル実装ような仕組みを構築しなくてもこれを使えば良さそうでした。 以下、調査や試した結果などを記載します。

アカウントレベルのサプレッションリストの有効化

2019年以前から使用している場合は、明示的に有効にしないといけないようです。

2019 年 11 月 25 日以降に Amazon SES の使用を開始した場合、アカウントはバウンスと苦情の両方に対してアカウントレベルのサプレッションリストをデフォルトで使用します。この日付より前に Amazon SES の使用を開始した場合は、Amazon SES API の PutAccountSuppressionAttributes オペレーションを使用してこの機能を有効にする必要があります。

アカウントレベルのサプレッションリストの使用 - Amazon Simple Email Service

バウンスと苦情の両方を有効にする場合は、以下のコマンドで有効にできるようです。

$ aws sesv2 put-account-suppression-attributes \
      --suppressed-reasons "BOUNCE" "COMPLAINT"

アカウントレベルのサプレッションリストの動作検証

挙動を試したかったので、適当なアドレスにメールを送信して確かめました。

※注意:今回は検証のためにやりましたが、適当なメールアドレスに送信すると当然バウンスレートが上がってしまうので、可能な限りやらないでください。ちなみに、私が個人で使っているAWSアカウントでやっています。

上記の有効化以外は、特に設定をしなくてもサプレッションリストに自動的に追加されました。

$ aws sesv2 list-suppressed-destinations 
{
    "SuppressedDestinationSummaries": [
        {
            "EmailAddress": "b33a624b-e250-4976-80f7-4fb6eec55165@gmail.com",
            "Reason": "BOUNCE",
            "LastUpdateTime": "2020-09-20T08:02:05.934000+00:00"
        }
    ]
}

この後同じメールアドレスに再送信してみましたが、実際に送信されませんでした。 またバウンスにもカウントされませんでした。 上記のサンプル実装のように自前で色々やらなくても、これだけで大体のケースをカバーできそうです!

なおテスト用の bounce@simulator.amazonses.com に送信してもサプレッションリストには追加はされないようです。

Gmail の苦情データについて

ドキュメントを読んでいると気になる記述がありました。

Gmail では、Amazon SES に苦情データが提供されません。受取人が Gmail ウェブクライアントの [迷惑メール] ボタンを使用して、受信したメールを迷惑メールとして報告した場合、アカウントレベルのサプレッションリストには追加されません。

アカウントレベルのサプレッションリストの使用 - Amazon Simple Email Service

Gmail の苦情(「迷惑メール」ボタン)に関しては自動で追加されないようです。 恐る恐る Gmail で「迷惑メール」ボタンをクリックしてみると・・・、苦情率も上がらず、設定している SNS での通知も来ませんでした。

どうしてなのか気になって調べてみると、苦情のデータはフィードバックループという仕組みで提供されているようです。 しかしながら Gmail はこのフィードバックループに対応していないようでした。

Gmailはいまや世界で最も有名なメールサービスとなりました。その中身はGoogle独自の技術でブラックボックス化されており、ホワイトリストやフィードバックループなど多くのISPで利用されている技術は利用されていません。

Gmail宛にメールを届けるための5つのポイント | SendGridブログ

正確には対応しているけれども、条件を満たした場合のみしか利用できないようです。

(※) Gmailもフィードバックループに対応していますが、利用可能なのは以下の条件を満たしているESPのみです。
 ・MAAWG(Messaging Anti-Abuse Working Group)のメンバーである
 ・Googleに「良い送信者」であると認められている

フィードバックループ【入門】 | SendGridブログ

Google は Postmaster Tools というツールを提供しているようです。 Gmail に関しては、こちらで迷惑メールを確認する必要があるようですね。

Postmaster Tools を使ってみる - Gmail ヘルプ

Gmail で「迷惑メール」ボタンを押されても、苦情率が上がるわけではないので AWS SES から送信できなくなることはなさそうです。 しかし多くのユーザーをもつ Gmail に迷惑メールと判定されるようになると、送信しても迷惑メールに振り分けられてしまうためこちらも注意する必要がありそうです。

おわりに

メールは歴史が長く、いろいろな場面で使われているため様々な対策が講じられています。

「うちのサービスはあんまりメールを送信していないから大丈夫」と思っていても、認証情報がスパム業者に漏れたりして大量のスパムメールを送られてしまい、サービスで必要なメールが送れなくなることもありえます。 (もちろん認証情報が漏れないようにすることが一番重要ですが)

バウンスや苦情が発生しないように、また発生しても素早く検知して対応し、安定してメールを使っていきたいですね。

PR

コネヒトではエンジニアを募集しています!

執筆時に参照した資料など

SendGrid さんのブログは、メールに関する様々な情報がまとまっていて、とても参考になります。