SendGridのInbound Email Parseを利用
SendGridは、メール配信などで利用されている方は多いのかもしれませんが、メール受信トリガーにWEB API経由でPOSTしてくれるサービスも提供されているようです。メール受信時のWEB APIプッシュの実現方法を探している際に見つけました。
グローバルで、企業向けにサービスを展開されているので、サービス品質などに間違いはなさそうです。
IFTTTでメール受信をしっかりとトリガー出来ていれば本サービスを利用することも無かったかもしれませんが、利用してみてPubSubというような使い方が出来そうなのでメインで利用する予定です。一般向け製品では通知手段がメールというサービスが多いです。
- 第1回 SendGridでの設定と自ドメインDNSの設定変更
- 第2回 SendGridよりPUSHされるWEB API準備(今回)
前提条件
- PHPが動作するWEBサーバがセットアップされている
- WEBサーバの公開設定が終わっている
- DNSで名前解決ができる、固定IPやダイナミックDNSを利用 SynologyでValueDomain向けのDDNS設定方法
- ルーターのNAT / Port Foward / Virtual Serverの設定が出来ており、インタネットからWEBサーバにアクセスできる API連携プラットフォーム
- (Raspberry Piの)https経由(SSL証明書)が設定済み
SendGridのInbound Email Parse向けPHP APIサンプル
WEBサーバーにPOST受信可能なPHPファイルを配置し、SendGridがメール受信したさいのWEBリクエストを受信するPHP APIを準備します。
以下は、サンプルとなります。受信後に実施したい処理を利用形態に合わせて実装して下さい。本ページの各種ユースケースもサンプルになると思います。ユースケース一覧 V1
- メール受信時にDBにレコード登録(モーションセンサ感知時にメール通知用)
- ホームセキュリティ通知をDBにレコード登録(活動ログとして)
- 各種速報メール受信時のLINE通知など
以下サンプルコードとなります。
<?php /************************************************************************* * sendgrid-api (MAIN) * Home Tools for private. Using IFTTT and Google Home etc * * PHP 5 or later * * @category Home IoT * @author Miki * @url https://www.miki-ie.com/ * @copyright 2019 (c) MIKI-IE All rights Reserved. * @license https://opensource.org/licenses/mit-license.html MIT License * @version 1.0 *************************************************************************/ //ログのファイル名 define("SENDGRID_API_LOG_NAME","sendgrid"); //DB define("DB_HOST","@IP_Adress@:@Port@"); define("DB_USER","@User@"); define("DB_PASS","@Password@"); define("DB_DBNAME","@DB_Name@"); define("DB_TABLENAME1","@TableName1@"); define("DB_TABLENAME2","@TableName2@"); function addDBRecord($table, $datetime, $value1) { $mysqli = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_DBNAME); if (mysqli_connect_errno()) { logger("Connect failed: ".mysqli_connect_error(),"ERROR"); exit(); } if (!$mysqli->set_charset("utf8")) { logger("Error loading character set utf8: ".$mysqli->error,"ERROR"); exit(); } switch ($table) { case DB_TABLENAME1: // SQL(INSERT)を作成 $sql = "INSERT INTO $table ( DATETIME, COUNT ) VALUES ( '$datetime', $value1 )"; break; //addDBRecord(DB_TABLENAME2, $datetime_text, $state_text); case DB_TABLENAME2: // SQL(INSERT)を作成 $str = mb_convert_encoding($value1, "UTF-8"); $sql = "INSERT INTO $table ( DATETIME2, STATE ) VALUES ( '$datetime', N'$str' )"; break; default: logger("Internal DB Tabel Name Error. table:{$table}","ERROR"); } if (!$mysqli->query($sql)) { logger("SQL query error Errormessage: ".$mysqli->error,"ERROR"); } $mysqli->close(); } function logger($text, $level) { $datetime = date('Y-m-d H:i:s'); $date = date('Ym'); $file_name = __DIR__ . "/log/".SENDGRID_API_LOG_NAME."-{$date}.log"; $text = "{$datetime} [{$level}] {$text}" . PHP_EOL; echo $text; if(!(file_exists($file_name))){ touch($file_name); chmod($file_name, 0777); } return error_log(print_r($text, TRUE), 3, $file_name); } $post_from = $_POST['from']; $post_charsets = $_POST['charsets']; $post_charsets_array = json_decode($post_charsets, true); $post_charsets_all = print_r($post_charsets_array, true); $post_encode_subject = mb_convert_encoding($_POST['subject'], "UTF-8", $post_charsets_array["subject"]); $post_encode_subject = preg_replace('/[\x00-\x1F\x7F]/', '', $post_encode_subject); $post_encode_text = mb_convert_encoding($_POST['text'], "UTF-8", $post_charsets_array["text"]); $post_encode_text = preg_replace('/[\x00-\x1F\x7F]/', '', $post_encode_text); logger("mb_convert_encoding, post_subject : {$post_encode_subject}","DEBUG"); logger("mb_convert_encoding, post_text : {$post_encode_text}","DEBUG"); $text_substr = mb_substr($post_text, 0, 15); logger("Start sendgrid: key={$key} , from={$post_from} , subject={$post_subject} , text={$text_substr}","INFO"); if(isset($_POST['from'])) { switch ($post_from) { case 'aaa1@bbb.ccc': //メール受信内容に合わせて個別処理。以下はメール本文から文字列切り出しを実施 $start = mb_strpos($post_text, "時刻:"); $datetime_text = mb_substr($post_text, $start + 4, 19,"utf-8"); logger("Start CAM-A7DE datetime : {$datetime_text}","INFO"); addDBRecord(DB_TABLENAME1, $datetime_text, 1); break; case 'aaa2@bbb.ccc': //メール受信内容に合わせて個別処理。以下はメール本文から文字列切り出しを実施 $datetime_text = mb_substr($post_text, 0, 16,"utf-8"); $temp_text = mb_substr($post_text, 18); $end_point = mb_strpos($temp_text, "。"); $state_text = mb_substr($temp_text, 0, $end_point,"utf-8"); logger("end_point : {$end_point} ,state : {$state_text}","DEBUG"); logger("Start CSP-Security datetime : {$datetime_text} state : {$state_text}","INFO"); addDBRecord(DB_TABLENAME2, $datetime_text, $state_text); break; default: logger("This is private API. (in Default)","ERROR"); } }else{ logger("This is private API. (in else)","ERROR"); } ?>
Inbound Email Parse WebhookのPOST情報
HEADERS | The raw headers of the email. |
---|---|
DKIM | A string containing the verification results of any DKIM and domain keys signatures in the message. |
CONTENT-IDS | A string containing the number of attachments. |
TO | Email recipient field, as taken from the message headers. |
HTML | HTML body of email. If not set, email did not have an HTML body. |
FROM | Email sender, as taken from the message headers. |
SENDER_IP | A string of the sender’s ip address. |
SPAM_REPORT | Spam Assassin’s spam report. |
ENVELOPE | A string containing the SMTP envelope. This will have 2 variables: to , which is a single-element array containing the address that we received the email to, and from , which is the return path for the message. |
ATTACHMENTS | Number of attachments included in email. |
SUBJECT | Email Subject. |
SPAM_SCORE | Spam Assassin’s rating for whether or not this is spam. |
ATTACHMENT-INFO | A JSON map where the keys are named attachment{X}. Each attachment key points to a JSON object containing three fields, filename , type , and content-id . The filename field is the name of the file (if it was provided). The type field is the media type of the file. X is the total number of attachments. For example, if the number of attachments is 0, there will be no attachment files. If the number of attachments is 3, parameters attachment1, attachment2, and attachment3 will have file uploads. |
CHARSETS | A string containing the character sets of the fields extracted from the message. |
SPF | The results of the Sender Policy Framework verification of the message sender and receiving IP address. |
[Date] array(16) { ["headers"]=> string(1970) "Received: by mx0047p1mdw1.sendgrid.net with SMTP id 6WCVv7KAWn Wed, 27 Jul 2016 20:53:06 +0000 (UTC) Received: from mail-io0-f169.google.com (mail-io0-f169.google.com [209.85.223.169]) by mx0047p1mdw1.sendgrid.net (Postfix) with ESMTPS id AA9FFA817F2 for <example@example.comom>; Wed, 27 Jul 2016 20:53:06 +0000 (UTC) Received: by mail-io0-f169.google.com with SMTP id b62so81593819iod.3 for <example@example.comom>; Wed, 27 Jul 2016 13:53:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sendgrid.com; s=ga1; h=mime-version:from:date:message-id:subject:to; bh=DpB1CYYeumytcPF3q0Upvx3Sq/oF4ZblEwnuVzFwqGI=; b=GH5YTxjt6r4HoTa+94w6ZGQszFQSgegF+Jlv69YV76OLycJI4Gxdwfh6Wlqfez5yID 5dsWuqaVJZQyMq/Dy/c2gHSqVo60BKG56YrynYeSrMPy8abE/6/muPilYxDoPoEyIr/c UXH5rhOKjmJ7nICKu1o99Tfl0cXyCskE7ERW0= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=DpB1CYYeumytcPF3q0Upvx3Sq/oF4ZblEwnuVzFwqGI=; b=Sq6LVHbmywBdt3sTBn19U8VOmelfoJltz8IcnvcETZsYwk96RBxN+RKMN5fOZSKw4j 15HrgdIFfyDmp67YK0ygvOITlTvZ6XY5I0PtnvDtAQt79kS3tKjI3QKJoEp/ZjIjSzlL KG7agl6cxFgBbIN0yHWBOvy3O+ZXY8tZdom1yOvULjmjW1U9JkdOs+aJ6zq4qhZX/RM/ tIgLB461eJ5V95iQDDc5Ibj9Cvy4vJfXLQRO0nLVQAT2Yz58tkEO1bDZpWOPAyUNneIL yhIWp+SpbuqhMA68mq0krG1PjmWalUbpVcGJIGuOKB9mQFFo/MqdrUCjvYnyo1jPLPeX psdQ== X-Gm-Message-State: AEkoousvdxmDoxLlTUYJ1AOmCGJv77xRBBlfKv6YrthH0M2NueMwlOxUD6t8nidE9uonXbdJ/DQy/chmHUnN//a4 X-Received: by 10.107.6.101 with SMTP id 98mr38024553iog.41.1469652785829; Wed, 27 Jul 2016 13:53:05 -0700 (PDT) MIME-Version: 1.0 Received: by 10.107.48.17 with HTTP; Wed, 27 Jul 2016 13:53:05 -0700 (PDT) From: Sender Name <example@example.com> Date: Wed, 27 Jul 2016 14:53:05 -0600 Message-ID: <CAN_P_JMvV7ZpAQhOnDienypLrJmuhN=LQWweu4yScw4jQyXY2w@mail.gmail.com> Subject: Different File Types To: example@example.comom Content-Type: multipart/mixed; boundary=001a113f8ad03e85160538a4343c " ["dkim"]=> string(22) "{@sendgrid.com : pass}" ["content-ids"]=> string(37) "{"ii_1562e2169c132d83":"attachment1"}" ["to"]=> string(26) "example@example.comom" ["html"]=> string(479) "<div dir="ltr">Here's an email with multiple attachments<div><br></div><div><img src="cid:ii_1562e2169c132d83" alt="Inline image 1" width="455" height="544"><br clear="all"><div><br></div>-- <br><div class="gmail_signature" data-smartmail="gmail_signature"><div dir="ltr"><img src="https://sendgrid.com/brand/sg-logo-email.png" width="96" height="17"><br><div><br></div></div></div> </div></div> " ["from"]=> string(33) "Sender Name example@example.com" ["text"]=> string(139) "Here's an email with multiple attachments " ["sender_ip"]=> string(14) "209.85.223.169" ["spam_report"]=> string(844) "Spam detection software, running on the system "mx0047p1mdw1.sendgrid.net", has identified this incoming email as possible spam. The original message has been attached to this so you can view it (if it isn't spam) or label similar future email. If you have any questions, see @@CONTACT_ADDRESS@@ for details. Content preview: Here's an email with multiple attachments [image: Inline image 1] -- [...] Content analysis details: (2.6 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.8 HTML_IMAGE_RATIO_02 BODY: HTML has a low ratio of text to image area 0.0 HTML_MESSAGE BODY: HTML included in message 1.8 HTML_IMAGE_ONLY_08 BODY: HTML: images with 400-800 bytes of words 0.0 T_MIME_NO_TEXT No text body parts " ["envelope"]=> string(66) "{"to":["example@example.comom"],"from":"example@example.com"}" ["attachments"]=> string(1) "2" ["subject"]=> string(20) "Different File Types" ["spam_score"]=> string(5) "2.597" ["attachment-info"]=> string(287) "{"attachment2":{"filename":"DockMcWordface.docx","name":"DockMcWordface.docx","type":"application/vnd.openxmlformats-officedocument.wordprocessingml.document"},"attachment1":{"filename":"MG_2359.jpg","name":"_MG_2359.jpg","type":"image/jpeg","content-id":"ii_1562e2169c132d83"}}" ["charsets"]=> string(77) "{"to":"UTF-8","html":"UTF-8","subject":"UTF-8","from":"UTF-8","text":"UTF-8"}" ["SPF"]=> string(4) "pass" }