Alexa SDK for Node.js Ver2を使ったメール送信とJSONによるデータの受渡し

Alexa SDK for Node.js Ver2を使って、nodemailerによるメール送信とJSONによるサーバとのデータの受渡しを行います。「Alexa SDK for Node.js Ver2をAWS Lambdaにデプロイ」で Alexa SDK for Node.js Ver2をAWS Lambdaにデプロイしました。この「node_modules」にメーラライブラリ「nodemailer」を追加してデプロイします。ここでは、次のスクリプトを作成します。

  • メーラライブラリ「nodemailer」によるメール送信
  • JSONによるサーバへのデータ送信
  • JSONによるサーバからのデータ受信

今回のスクリプトではASK SDK v1アダプター「ask-sdk-v1adapter」を使用します。これはV2でメール送信とJSONによるデータの受け渡しの方法が調べきれなかったためです。V2でスクリプトを作成すると、応答が返ってくる前にスクリプトが終了してしまします。

メーラライブラリ「nodemailer」のデプロイ

Raspberry piに作成したカスタムスキルを開発するローカルな開発環境で、次のコマンドでASK SDK v1アダプター「ask-sdk-v1adapter」とメーラライブラリ「nodemailer」をインストールし、作成したフォルダ/ファイルをzipファイルとして圧縮します。ただし、「aws-sdk」はフォルダが大きいため、Web上の「コードをインラインで編集」が利用できないので、削除してAWS Lambdaにデプロイは行いません。

$ npm install --save  ask-sdk-v1adapter ask-sdk
$ npm install nodemailer
$ npm install nodemailer-smtp-transport

メーラライブラリ「nodemailer」によるメール送信

AWS Lambdaのindex.jsに次のスクリプトを記述し、メーラライブラリ「nodemailer」によりメールの送信が完了すると、Amazon Echoに「メールを送信しました」と発話させます。

  • 2行目:ASK SDK v1アダプター「ask-sdk-v1adapter」を指定します。
  • 6-10行目:ASK SDK v1アダプター「ask-sdk-v1adapter」で動作させるときはこのように変更します。
  • 28-34行目:メールサーバへの接続情報を設定します。
  • 29-44行目:送信するメールの内容を設定します。

index.js

'use strict';
const Alexa = require('ask-sdk-v1adapter');

var APP_ID = undefined;

exports.handler = function (event, context, callback) {
    var alexa = Alexa.handler(event, context);
    alexa.APP_ID = APP_ID;
    alexa.registerHandlers(handlers);
    alexa.execute();
};

var handlers = {
    'LaunchRequest': function () {
        this.emit('GetNewFactIntent');
    },

    'GetNewFactIntent': function () {
        var te = this;
        var targetEmail = 'xxxx';
        var fromEmail = 'xxxx';
        var sesAccessKey = 'xxxx';
        var sesSecretKey = 'xxxx';

        var nodemailer = require('nodemailer');
        var smtpTransport = require('nodemailer-smtp-transport');

        var transporter = nodemailer.createTransport(smtpTransport({
            host: 'xxxxx',
            port: 587,
            auth: {
                user: sesAccessKey,
                pass: sesSecretKey
            }
        }));

        var text = 'Tomoでございます。';

        var mailOptions = {
            from: fromEmail,
            to: targetEmail,
            subject: '問い合わせ',
            text: text
        };

        transporter.sendMail(mailOptions, function (error, info) {
            if (error) {
                console.log(error);
            }
            te.emit(':tell', 'メールを送信しました');
        });
    }
};

AWS Lambda画面右上の「テスト」ボタンをクリックして作成した「index.js」を実行すると、次のような応答がAWS Lambda画面上に表示されます。また、Amazon開発者コンソールに紐づいたAmazon Echoからどのような音声を入力しても、「メールを送信しました」とAmazon Echoが答え、指定したメールの宛先にメールが届きます。

Response:
{
  "version": "1.0",
  "response": {
    "shouldEndSession": true,
    "outputSpeech": {
      "type": "SSML",
      "ssml": "メールを送信しました"
    }
  },
}

JSONによるサーバへのデータ送信

AWS Lambdaのindex.jsに次のスクリプトを記述し、httpライブラリ「http」によりJSON形式のデータをWebサーバに送信し、送信が完了すると、Amazon Echoに「データを送信しました」と発話させます。

  • 2行目:ASK SDK v1アダプター「ask-sdk-v1adapter」を指定します。
  • 6-10行目:ASK SDK v1アダプター「ask-sdk-v1adapter」で動作させるときはこのように変更します。
  • 23-26行目:送信するデータをJSON形式で記述します。
  • 29-38行目:対象リソースの通信オプション「options」を使ってHTTPのパラメータ設定します。

index.js

'use strict';
const Alexa = require('ask-sdk-v1adapter');

var APP_ID = undefined;

exports.handler = function (event, context, callback) {
    var alexa = Alexa.handler(event, context);
    alexa.APP_ID = APP_ID;
    alexa.registerHandlers(handlers);
    alexa.execute();
};

var handlers = {
    'LaunchRequest': function () {
        this.emit('GetNewFactIntent');
    },

    'GetNewFactIntent': function () {
        let http = require('http');
        const HOST = `xxxx`;
        const PATH = `xxxx/postdata.php`;

        let postData = {
            "name": "TomoSoft8",
            "comment": "good soft"
        };

        let postDataStr = JSON.stringify(postData);
        let options = {
            host: HOST,
            port: 80,
            path: PATH,
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Content-Length': postDataStr.length
            }
        };

        let req = http.request(options, (res) => {
            console.log('STATUS: ' + res.statusCode);
            console.log('HEADERS: ' + JSON.stringify(res.headers));
            res.setEncoding('utf8');
            res.on('data', (chunk) => {
                console.log('BODY: ' + chunk);
                this.emit(':tell', 'データを送信しました');
            });
        });
        req.on('error', (e) => {
            console.log('problem with request: ' + e.message);
        });
        req.write(postDataStr);
        req.end();
    }
};

webサーバに置かれ、AWS Lambdaのindex.jsのスクリプトから呼ばれる「postdata.php」を次に示します。index.jsのスクリプトから呼ばれと、ファイル「samplepost.txt」に入力情報を保存し、JSON形式で渡された情報を応答として返します。

postdata.php

<?php
try {
	$headers = getallheaders();
	$post_body = file_get_contents('php://input');
	
	$fp = fopen("samplepost.txt", "w");
	foreach ($headers as $name => $value) {
		fwrite($fp,"$name: $value\n");
	}
	fwrite($fp,"$post_body\n");
	fclose($fp);

	$obj = json_decode($post_body);  // オブジェクト形式
	if ($obj === NULL) return;
	var_dump($obj);
	echo "<br>";
	echo $obj->{'payload'}->{'channels'}[0]->{'value'};
	echo "<br>";
	echo $obj->{'datetime'};
	echo "<br>";

} catch (PDOException $e){
    var_dump($e->getMessage());
}
?>

AWS Lambda画面右上の「テスト」ボタンをクリックして作成した「index.js」を実行すると、次のような応答がAWS Lambda画面上に表示されます。console.logコマンドにより、応答のステータス、ヘッダ、戻り値を表示します。また、Amazon開発者コンソールに紐づいたAmazon Echoからどのような音声を入力しても、「データを送信しました」とAmazon Echoが答え、指定したWebサーバにデータが届きます。

Response:
{
  "version": "1.0",
  "response": {
    "shouldEndSession": true,
    "outputSpeech": {
      "type": "SSML",
      "ssml": "データを送信しました"
    }
  },
}


Function Logs:
2018-07-21T04:11:59.611Z	STATUS: 200
2018-07-21T04:11:59.611Z	HEADERS: {"server":"nginx","date":"Sat, 21 Jul 2018 04:11:59 GMT","content-type":"text/html; charset=UTF-8","transfer-encoding":"chunked","connection":"close","x-powered-by":"PHP/7.1.19"}
2018-07-21T04:11:59.613Z	BODY: object(stdClass)#1 (2) {

2018-07-21T04:11:59.613Z	BODY:   ["name"]=>
  string(9) "TomoSoft8"
  ["comment"]=>
  string(9) "good soft"
}

ファイル「samplepost.txt」に保存された入力情報を次に示します。JSON形式でデータが渡されていることがわかります。

samplepost.txt

Host: tomosoft.jp
X-Real-Ip: 18.179.31.112
X-Forwarded-Proto: http
Listen-Ipaddr: 49.212.207.43
Content-Length: 42
Content-Type: application/json
{"name":"TomoSoft8","comment":"good soft"}

JSONによるサーバからのデータ受信

AWS Lambdaのindex.jsに次のスクリプトを記述し、httpライブラリ「http」によりJSON形式のデータをWebサーバに送信し、送信が完了すると、Amazon Echoに「データを送信しました」と発話させます。

  • 2行目:ASK SDK v1アダプター「ask-sdk-v1adapter」を指定します。
  • 6-10行目:ASK SDK v1アダプター「ask-sdk-v1adapter」で動作させるときはこのように変更します。
  • 23-31行目:対象リソースの通信オプション「options」を使ってHTTPのパラメータ設定します。
  • 41行目:JSON形式で受信したデータを使って、発話を編集します。

index.js

'use strict';
const Alexa = require('ask-sdk-v1adapter');

var APP_ID = undefined;

exports.handler = function (event, context, callback) {
    var alexa = Alexa.handler(event, context);
    alexa.APP_ID = APP_ID;
    alexa.registerHandlers(handlers);
    alexa.execute();
};

var handlers = {
    'LaunchRequest': function () {
        this.emit('GetNewFactIntent');
    },

    'GetNewFactIntent': function () {
        let http = require('http');
        const HOST = `xxxx`;
        const PATH = `xxxx/getdata.php`;

        let options = {
            host: HOST,
            port: 80,
            path: PATH,
            method: 'GET',
            headers: {
                'Content-Type': 'application/json',
            }
        };

        let req = http.request(options, (res) => {
            res.setEncoding('utf8');

            res.on('data', (chunk) => {
                var parsedValue = JSON.parse(chunk);
                var key1 = "price";
                console.log(parsedValue);
                console.log(parsedValue[key1]);
                this.emit(':tell', String(parsedValue['price']) + 'えんです');
            });

        }).on('error', (e) => {
            console.log(e.message); //エラー時
            this.emit(':tell', 'エラーです' + e.message);
        });
        req.end();
    }
};

webサーバに置かれ、AWS Lambdaのindex.jsのスクリプトから呼ばれる「getdata.php」を次に示します。index.jsのスクリプトから呼ばれと、JSON形式で情報「'{“price”:500, “item”:”card” , “date”:”2018/11/05″}’」を返します。

getdata.php

<?php
try {
	// ヘッダーを指定
	header( "Content-Type: application/json; charset=utf-8" ) ;
	
	$fp = fopen("sampleget.txt", "w");
	fwrite($fp,"123\n");
	fclose($fp);
	
	$post_body = '{"price":500, "item":"card" , "date":"2018/11/05"}';

	echo $post_body ;
} catch (PDOException $e){
    var_dump($e->getMessage());
}
?>

AWS Lambda画面右上の「テスト」ボタンをクリックして作成した「index.js」を実行すると、次のような応答がAWS Lambda画面上に表示されます。Webサーバから受信したデータを、console.logコマンドにより表示します。また、Amazon開発者コンソールに紐づいたAmazon Echoからどのような音声を入力しても、指定したWebサーバからデータを受信し、受信したデータから「500えんです」とAmazon Echoが答えます。

Response:
{
  "version": "1.0",
  "response": {
    "shouldEndSession": true,
    "outputSpeech": {
      "type": "SSML",
      "ssml": "500えんです"
    }
  },
}

2018-07-21T04:35:46.326Z  { price: 500, item: 'card', date: '2018/11/05' }
2018-07-21T04:35:46.327Z  500