S3+Lambda+SESでのフォーム作成

S3+Cognito+Lambda+SESでのフォーム作成

WEBページをS3+CloudFrontに移したので問い合わせフォームが使えなくなり、せっかくなのでAWSの機能を組み合わせてみようと思ったところ

http://qiita.com/takuma_yoshida/items/3bd3af8b09307d25981a

先人の方が作っていたようなので、AWSのドキュメントと突き合わせつつ作成
*ついでにIE5の時代で止まっていたJavaScriptの勉強しなおしも兼ねて…

regionはSESのみus-east、後のサービスは東京に統一して作成。


以下、参考先から弄ったところを列挙

### Lambdaの設定

##### 設定
Lambda側ではinquiry_ + .txtのものがPutされた場合に関数が走るよう設定を行う


##### ポリシー

Lambda上で関数を作成する際のポリシー作成でSES権限を付与してもses.SendBounceの権限で作成される為、ses.SendEmailで送ろうとしている場合、当然許可はされず送信は出来ない
そのため、ポリシー選択でAmazonSESの権限は追加せず、S3の権限のみを選択し、関数を作成
その後、ses.sendEmailの権限を付与するカスタムポリシーを作成し、IAMロールに追加する

```json:SES
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Stmt1505896993000",
            "Effect": "Allow",
            "Action": [
                "ses:SendEmail"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}
```



#### フォームのJS

```javascript:index.js
    'use strict';
    const $id = function (id) { return document.getElementById(id); };

    AWS.config.region = 'ap-northeast-1'; // リージョン
    AWS.config.credentials = new AWS.CognitoIdentityCredentials({
      IdentityPoolId: 'ap-northeast-1:xxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
    });
    AWS.config.credentials.get(function (err) {
      if (err) {
        return alert('初期化に失敗しました。')
      }
    });

    const upload = function () {

      AWS.config.region = "ap-northeast-1";
      const s3BucketName = "inquiry.example.com";
      const date = new Date();

      const mail_param = {
        "name": $id("name").value
        , "kana": $id("kana").value
        , "company": $id("company").value
        , "tel": $id("tel").value
        , "mail": $id("mail").value
        , "date": date.toLocaleString("ja")
      };

      const s3 = new AWS.S3({ params: { Bucket: s3BucketName } });
      const blob = new Blob([JSON.stringify(mail_param)], { type: 'text/plain' });

      s3.putObject(
        {
          Key: `inquiry_${date.getTime()}.txt`
          , ContentType: "text/plain"
          , Body: blob
          , ACL: "private"
        },
        function (err, data) {
          if (err) {
            console.log(err, err.stack);
            return alert(err.message);
          } else {
            location.assign("./thanks.html");
          }
        }
      );
    };
```

#### LambdaのJS


```js:mail.js
'use strict';

console.log('Loading function');

const aws = require('aws-sdk');
const s3 = new aws.S3({ apiVersion: '2006-03-01' });
const ses = new aws.SES({ apiVersion: '2010-12-01', region: 'us-east-1' });

exports.handler = (event, context, callback) => {
    const bucket = event.Records[0].s3.bucket.name;
    const key = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, ' '));
    const params = {
        Bucket: bucket,
        Key: key
    };

    s3.getObject(params, (err, data) => {
        if (err) {
            console.log(err);
            const message = `Error getting object ${key} from bucket ${bucket}. Make sure they exist and your bucket is in the same region as this function.`;
            console.log(message);
            callback(message);
        } else {
            const json = JSON.parse(data.Body.toString());
            console.log(`title:${json.title}`);

            const message = `
                名前： ${json.name}(${json.kana})            
                会社： ${json.company}
                TEL：  ${json.tel}
                MAIL： ${json.mail}
                問合せ日時：
                ${json.date}
                `

            const params = {
                Destination: {
                    ToAddresses: [process.env.TOADDRESS]
                },
                Message: {
                    Body: {
                        Text: {
                            Charset: "UTF-8",
                            Data: message
                        }
                    },
                    Subject: {
                        Charset: "UTF-8",
                        Data: "フォームからのお問い合わせ"
                    }
                },
                Source: process.env.SOURCEADDRESS
            };
            ses.sendEmail(params, function (err, data) {
                if (err) console.log(err, err.stack);
                else console.log(data);
            });

        }
    });
};
```

### 引っかかったところ

#### S3への書き込み権限エラー

S3にアップロードする際に、権限のエラーでアップロードが出来ない
ARNはバケットのプロパティからコピーした筈だから…とハマる

##### エラー時のポリシー

```json:policy.before
"Resource": [
       "arn:aws:s3:::inquiry.example.com"
]
```

ARNをS3のバケットに対してのものと勘違いし、バケットのARNをそのままコピペした所
ファイルに対しての権限が無いため、アップロードがエラーに… 

https://docs.aws.amazon.com/ja_jp/general/latest/gr/aws-arns-and-namespaces.html

##### 修正したポリシー

```json:policy.after
"Resource": [
       "arn:aws:s3:::inquiry.example.com/*"
]
```