まだプログラマーですが何か?

プログラマーネタとアスリートネタ中心。たまに作成したウェブサービス関連の話も http://twitter.com/dotnsf

タグ:sendgrid

メール送信(送信だけじゃないけど)サービスの最大手と思われる SendGrid を使う機会がありました。SDK や API を使って、メールを送信できるサービスです。
2016090601


メール送信そのものは(sendmail などを使えば)単純に実現できますが、一度に大量のメールを送る場合や迷惑メール対策など、本格的に使おうとすると色々な面倒が待っています。そういう面倒な所を一手に引き受けて、心配なくメール送信が実現できる、というサービスです。

この SendGrid によるメール送信ですが、ダッシュボード画面から目的の相手にインタラクティブに送信するだけではなく、プログラミングのためのインターフェースが公開されているので、自分の作るアプリケーションから利用することもできます。ただ実際に送信するサンプルを Java でググると、多くの場合 SDK を使ったものが見つかります。自分は SDK ではなく Web API(REST API) での実現を考えていたので挑戦してみました。ウェブ上にあまり資料がなかったこともあって、その手順を以下に紹介します。


まず最初に大事なこと。SendGrid Web API の最新バージョンは V3 ですが、V2 を使います。SendGrid の推奨でもあります:
https://support.sendgrid.kke.co.jp/hc/ja/articles/206231901-Web API v2とv3どちらを利用すべきでしょうか?-


というわけで、Web API V2 の Mail API を使って実装することにします。リファレンスはこちらです:
https://sendgrid.kke.co.jp/docs/API_Reference/Web_API/mail.html


これを読むと、「メールを送信して結果を JSON で受け取る」場合は以下の様な REST API を実行することになります(これは curl コマンドで実行する場合の例):
$ curl -X POST https://api.sendgrid.com/api/mail.send.json -H 'Authorization:Bearer SG.*****' -d 'to=user1@recipient.com&subject=abcd&from=info@from.com&html=<b>ハロー</b>、ワールド'

上記コマンドは info@from.com ユーザーから user1@recipient.com ユーザーへ、メールサブジェクトは "abcd" 、本文は HTML で "<b>ハロー</b>、ワールド"(HTML として送信しているので、ハローだけが太字になります)を送信する場合のコマンドになります。 user1@recipient.com は送信先なので実在している必要がありますが、送信アドレスである info@from.com は実在している必要はありません。またヘッダの認証情報として使っている SG. で始まる文字列は SendGrid から取得した api key です。SendGrid のアカウントをお持ちで、まだ api key を取得していない場合、取得方法についてはこちらを参照してください。

上記 curl コマンドは(入力ミスなどがなければ)正しく実行されて、メールも送信されるはずです。つまり正しいコマンドです。これを REST API と見なして、同じ処理を Java で実装しなおせばいいわけですが、これが意外と手間取りました。

まず最初に、普段使っている Jakarta Commons HTTP Client 3.1 (メンテナンスモード)を使って、こんなコードを書いてみました(あらかじめ書いておきますが、以下のコードでは期待通りに動きません):
  :
public int sendMail( String to, String subject, String html ){
  int r = 0;

  try{
    String data = "to=" + to + "&from=info@from.com&subject=" + subject + "&html=" + html;
    PostMethod method = new PostMethod( "https://api.sendgrid.com/api/mail.send.json" );
    method.setRequestHeader( "Authorization", "Bearer SG.*****" );
    method.setRequestBody( data );
    HttpClient client = new HttpClient();
    int sc = client.executeMethod( method );
    String json = method.getResponseBodyAsString();
      :
r = 1; }catch( Exception e ){ mothod.setRequest e.printStackTrace();
r = -1; } return r; } :

オプションで指定している内容は curl コマンドのものと同じです(例えば Content-Type ヘッダを指定していませんが、curl でも指定せずに動いていたので)。ただこの sendMail 関数を to = user1@recipient.com, subject =  abcd, html = <b>ハロー</b>、ワールド というパラメータで実行した場合、ステータスコード(上記コード内の sc 変数)の値は 400 となり、また実行結果である json 変数の値は以下のようなものになりました:
{"errors":["Empty from email address (required)"],"message":"error"}

「必須項目である from 値が空である」というエラーメッセージのように見えます。しかしその値は上記のようにハードコーディングで入力しているつもりでした。

これまでも HTTP Client を Java で実装する場合はこの HTTPClient 3.x を使うことが多かったし、今回のようなポスト時のエラーに遭遇したことはなかったのですが・・・ まずここで躓きました。


次に試したのはポスト方法の変更です。sendMail 関数を以下の様な形に変え、ポストデータをプレーンテキストで送信するのではなく NameValuePair 配列で送信するように変更してみました(これもまだ期待通りには動きません):
  :
public int sendMail( String to, String subject, String html ){
  int r = 0;

  try{
    PostMethod method = new PostMethod( "https://api.sendgrid.com/api/mail.send.json" );
    method.setRequestHeader( "Authorization", "Bearer SG.*****" );
    List<namevaluepair> params = new ArrayList<namevaluepair>();
    params.add( new NameValuePair( "to", to ) );
    params.add( new NameValuePair( "from", "info@from.com" ) );
    params.add( new NameValuePair( "subject", subject ) );
    params.add( new NameValuePair( "html", html ) );
    method.setRequestBody( ( NameValuePair[] )params.toArray( new NameValuePair[0] ) );
    HttpClient client = new HttpClient();
    int sc = client.executeMethod( method );
    String json = method.getResponseBodyAsString();
      :
    r = 1;
  }catch( Exception e ){
    mothod.setRequest
    e.printStackTrace();
    r = -1;
  }

  return r;
}
  :

自分としては先程のコードと同じことを記載しているつもりでした。が、このコードは一応動いて、ステータスコードは 200 (成功)を返してくれます。

しかし、実際に送られてくるメールを受け取ると、残念ながら日本語部分が全て ? という文字に化けてしまっていました。。
2016090601
 (↑ ハロー、ワールド という結果を期待していたが文字化け)


文字化けということは文字コードの指定と実際の文字コードが違っていると読み、であれば強制的に UTF-8 で指定すれば・・・ と考えたのですが、この HTTPClient 3.1 には Content-Type で指定する以外の文字コード指定方法はありません( NameValuePair 配列で指定した本文がどのような内部処理をされているのかはわかりません。。) というわけで、この方法も詰み・・・

結論として、HTTPClient のバージョンをより新しいものに上げて対処しました。現在の最新バージョンは 4.5.2 のようです(僕は 4.5.1 を使いました):
https://hc.apache.org/httpcomponents-client-ga/

このライブラリに置き換えた上で、コードも以下のように 4.5.x 仕様に書き換えました(完成版です):
  :
public int sendMail( String to, String subject, String html ){
  int r = 0;

  try{
    PostMethod method = new PostMethod( "https://api.sendgrid.com/api/mail.send.json" );
    method.setRequestHeader( "Authorization", "Bearer SG.*****" );
    List<namevaluepair> params = new ArrayList<namevaluepair>();
    params.add( new BasicNameValuePair( "to", to ) );
    params.add( new BasicNameValuePair( "from", "info@from.com" ) );
    params.add( new BasicNameValuePair( "subject", subject ) );
    params.add( new BasicNameValuePair( "html", html ) );
    method.setEntity( new UrlEncodedFormEntity( params, "UTF-8" ) );
    CloseableHttpClient client = HttpClients.createDefault();
    CloseableHttpResponse response = client.execute( method );
    int sc = response.getStatusLine().getStatusCode();
    HttpEntity entity = response.getEntity();
    String json = EntityUtils.toString( entity, StandardCharsets.UTF_8 );
      :
    r = 1;
  }catch( Exception e ){
    mothod.setRequest
    e.printStackTrace();
    r = -1;
  }

  return r;
}
  :

この関数は期待通りに動き、実行後にメールを受け取ると、期待通りの HTML コンテンツが文字化けなしに表示されました:
2016090602


と、偉そうに書きましたが、実の所、なぜ前の2つのコードで動かないのかわかりません。最新コードでは NameValuePair 配列を UTF-8 指定で追加していて、これは旧バージョンにはない関数なので、その差で文字化けの有無になっているのかもしれません。ただ繰り返しますが、curl では最小限の指定だけで動いていたことと同じ指定をしているのに、Java でうまく動かない理由が説明できないのでした(少なくともエラーメッセージの内容をそのまま信用して対処しようとするとハマりそうな予感・・・)。

まあとりあえずは結果オーライ、ということで。あと SendGrid のメール送信を Java から、それも SDK ではなく Web API 経由で送る例はあまり見かけることがなかったので、後からやる人の助けになれば嬉しいです。


IBM Bluemix を使うと、自分専用の WordPress 環境を手に入れることができます。

IBM Bluemix は IBM が提供する PaaS のサービスです。本来有償のサービスですが、最長30日間の無料トライアル期間と、トライアル終了後は特定条件下で使う場合に限り無料枠を使った継続利用ができます(無料枠を超えて利用した場合だけ課金されます)。

この無料枠の範囲内であれば、1ヶ月とか1年といった期間の制約なしにアプリケーションサーバーやデータベースサービスを利用することができます。今回はこの無料枠内で利用できるサービスの例としてブログやコンテンツ管理システムとして使われることの多い WordPress サイトを構築する手順を紹介します。なお、以下の内容は 2015/02/20 時点での内容であり、今後変更の可能性があることを留意ください。


まず、以下の作業を無料トライアル期間(サインアップから1ヶ月)内に限って行う場合はいいのですが、無料トライアル期間を超えて運用したい場合は、有償アカウントに移行する必要があります。有償アカウントに移行しても、ここで紹介するアプリケーション・サーバーとサービスのみを使う場合は無料枠内で運用できます(他のサーバーも併用する場合は無料枠を超える可能性もあります)。 トライアルアカウントを有償アカウントに変更するための手順はこちらを参照ください:
IBM Bluemix をトライアル期間(1ヶ月)を超えても無料で使う


では改めて IBM Bluemix 内に WordPress 環境を構築する手順を紹介します。まず IBM Bluemix にログインし、画面右上のデータセンターを「米国南部」にします。2015/02/20 時点で、「英国」データセンターでは以下で紹介する "WordPress on Bluemix" ボイラープレートが定義されていないため、構築の手続きが複雑になります。 今回は「米国南部」データセンターを使う、より簡単な方法を紹介します。 

そして画面上部の「カタログ」を参照すると、"WordPress on Bluemix" というボイラープレート(必要なアプリケーションとサービスを予め定義し、紐付けたテンプレート)が現れるので、これをクリックします:
2015022001


"WordPress on Bluemix" ボイラープレートの内容が表示されます。これを見ると PHP アプリケーション・サーバーに加え、ClearDB(MySQL)、Object Strage、SendGrid という3つのサービスがセットになっていることが分かります。これらを使って WordPress 環境を構築するテンプレートのようです。ここで画面右に一意になる名前(この例では dotnsf-wp)とホスト名(この例では dotnsf-wp)を入力して、最後に「作成」ボタンをクリックします:
2015022002


しばらく待つと ClearDB, Object Strage, SendGrid の3つのサービスがバインドされた状態で PHP アプリケーション・サーバーが起動します:
2015022003


改めて、ここで3つのサービスの利用料金について確認します。2015/02/20 時点ですが、これらのサービスの利用料金は以下のようになっています。制約こそありますが、無料枠の中で利用していくことができそうです:
サービス 利用料金 制約 参照
ClearDB 無料 DBサイズ 5MB、同時コネクション数 4、I/O 低、日次バックアップ有 参照
Object Strage 無料 ベータ版 参照
SendGrid 無料 月25000通までのメッセージ送信 参照


これらのサービスですが、ClearDB の実体は MySQL であり、用途としてはデータストアとして利用されます。Object Strage は画像などのメディアファイルのアップロード先として利用されます。これによってアプリケーション・サーバーが複数台構成になっても正しくメディアを取得できるような対応が可能になります。 また SendGrid はメッセージ送信サービスであり、構築した WordPress 環境のメール送信サービスとして利用します。これら3つのサービスと一緒に WordPress 本体が(PHP サーバー上で)動く、ということになります。 WordPress 環境を1インスタンスで作るだけならデータストアサービスがあればできるのですが、これらのサービスを組み合わせることで初めから IBM Bluemix の複数インスタンス機能に対応することができるようになります。その環境を簡単に構築するためのボイラーテンプレートが用意されている、ということになります。



アプリケーション・サーバーの起動後に名前部分(この例では dotnsf-wp)をクリックすると、アプリケーションサーバーインスタンスの状態が表示されます。メモリは 512MB で1インスタンス。メモリ量に限った計算ですが、これならば IBM Bluemix の無料枠内(月間750GB/H)でも運用可能です。有償アカウント移行後にこの状態よりもメモリを増やしたり、インスタンス数を増やしたりすると無料枠を超える可能性があることに注意してください。 そして「経路」と書かれた箇所に書かれた URL がこのアプリケーションが稼働している URL になります:
2015022004


コピペするなどして、この URL にアクセスしてみましょう。最初だけは WordPress の設定画面が表示され、まず言語を指定します。この例では「日本語」を指定しています:
2015022005


続けてサイトやサイト管理者の情報を入力します。最後に「WordPress をインストール」ボタンをクリックして設定は完了です:
2015022006


設定後に改めてアプリケーション URL にアクセスすると、WordPress の画面が表示されます。なお設定した管理者情報を使ってログインしていると最上段にユーザー情報も表示されます:
2015022007


試しに管理画面(http://(アプリケーションURL)/wp-admin/)にアクセス&ログインして WordPress のプラグイン情報を確認してみます。最初から IBM Object Strage や SendGrid 等のプラグインが導入されており、一部はすでに有効化されていることがわかります:
2015022008


またデフォルトのテーマは "Bluemix Style" と名付けられているようですが、パッと見で "Twenty Fourteen" テーマをコピーしたもののように見えますね。これがベースになっているのだと思います:
2015022009


最後にテーマを変更して見栄えを変えてみます。管理画面の「外観」メニューからテーマの「新規追加」を選び、検索するなどして適当なテーマを選んでインストールします。この例ではカッコよさげな "Tanzanite" という無料テーマを選んでみました:
2015022010


テーマをインストールして、有効化して、改めてトップページにアクセスするとこんな感じ。先ほどとはかなり印象の違うページになりました:
2015022011


ここまでの WordPress 環境がこれだけの手順で、しかも無料で手に入る、ということになります。結構魅力的では?

無料枠を超える話にはなりますが、仮にアクセス数などが急増して1サーバーだけでの対応が難しくなった場合は IBM Bluemix 上のサーバーインスタンスを増やしたり、メモリ数を調整したりもできるので、「本格的な利用を前提とした WordPress サービスの初期運用」にぴったりの環境だと思います。













 

このページのトップヘ