iOSからメールを送信するには(AMAZON SES編)


iOSより、MFMailComposeViewControllerを利用せずに裏の処理でメールを送信するため、以下の二通りを試した。

* [PARSE](http://parse.com)+[Mailgun](http://mailgun.com)
* [AMAZON SES](http://aws.amazon.com/jp/ses/)


ここでは、AMAZON SESについて記載します。とりあえず簡単に。
(参考：[Sending E-mail with Amazon SES Using the AWS SDK for iOS and the AWS SDK for Android](http://aws.amazon.com/articles/3290993028247679))

##1. amazon web serviceのアカウントを作成する
[amazon web service](http://aws.amazon.com/jp/)よりアカウントの作成を行います。

##2.IAMの設定を行う。
IAMからユーザー登録をします。ユーザーには、AWSで利用できるパーミッションを設定できます。ここでは、"AmazonSESFullAccess"を指定します。
Access key IDと、Secret Access Keyを覚えておく。特に、Secret Access Keyは後で確認できません。


##3.amazon sesで設定を行う
気をつける必要があるのは、
1.送信元アドレスは、登録したドメイン、またはアドレスのみ利用できる。
2.最初はsandboxモードになっており、この場合は送信先も同様に登録したものしか利用できない。
3.productionモードの申請を行う事で、登録外のアドレスに送信できる。

##4.xcodeよりコーディングを行う。
[SDK](http://aws.amazon.com/jp/sdkforios/)をダウンロードし、AmazonRuntime.frameworkと、AWSSES.frameworkをimportします。後は登録したユーザーのaccess_key,secret_keyでAmazonSESClientを初期化し、メール送信を行います。

```objectivec

#import <AWSRuntime/AWSRuntime.h>
#import <AWSSES/AWSSES.h>

-(void)sendMail{
    AmazonSESClient *sesClient = [[AmazonSESClient alloc] initWithAccessKey:ASES_ACCESS_KEY withSecretKey:ASES_SECRET_KEY];
    
    SESContent *subject = [[SESContent alloc] init];
    subject.data = @"Hello";

    SESContent *messageContent = [[SESContent alloc] init];
    messageContent.data = @"world!";

    SESBody *body = [[SESBody alloc] init];
    body.text = messageContent;

    SESMessage *message = [[SESMessage alloc] init];
    message.body = body;
    message.subject =subject;
    
    SESDestination *destination = [[SESDestination alloc] init];
    [destination addToAddresse:TO_ADDRESS];
    
    SESSendEmailRequest *request = [[SESSendEmailRequest alloc] init];
    request.source = FROM_ADDRESS;
    request.message = message;
    request.destination = destination;
    
    @try {
        SESSendEmailResponse *response = [sesClient sendEmail:request];
        NSLog(@"%@",[response description]);
    }
    @catch (AmazonServiceException *exception) {
        NSLog(@"%@",[exception description]);
    }
    @catch (AmazonClientException *exception) {
        NSLog(@"%@",[exception description]);
    }
    

}
```

##5.送信できない場合
 以下のエラーが表示されて送信ができなかった。

```
SESSender[6099:60b] {SESMessageRejectedException { RequestId:******************, ErrorCode:MessageRejected, Message:Email address is not verified. }}
```
チェック事項はこんな感じかな。

1. productionモードになっているか。
2. 送信元アドレスがverifiedになっているか。
3. 送信元アドレスからテストメールが送信できるか。(SES Management Console > Verified Senders > Send a Test Email より)
4. APIより、登録したアドレス、ドメイン(identities)が取得できるかを確認。([*1](#star1))
5. APIより、通信先のエンドポイントを確認 or 選択したエンドポイントに変更する。([*2](#star2))

自分がはまっていたのは4.でidentitiesが取得できない事。原因は5.のエンドポイントでした。SES Management Consoleの右上部で、US.West (Oregon)を選択して設定をしていたが、デフォルトではUS.East(email.us-east-1.amazonaws.com)のためidentitiesが取得できていなかった。[AMAZON SES公式blog](http://sesblog.amazon.com/post/Tx2XFRQ8H3EXCZL/Amazon-SES-Expands-to-US-West)から引用すると、
> The first thing you need to do is to configure the sending identities you want to send from in the new region. Your verified domains and email addresses are not shared between regions, and neither are identity-related settings (such as DKIM or feedback notifications). You can set them up in the new region while still having your application send from the old one:

詳しくは[ここ](http://docs.aws.amazon.com/ses/latest/DeveloperGuide/regions.html#region-select)とか[ここ](http://docs.aws.amazon.com/ses/latest/DeveloperGuide/regions.html)を参照。とりあえず、([*2](#star2))のようにendpointを指定してあげました。


<a name="star1">*1 APIを利用したidentitiesの取得</a>

```objectivec

    AmazonSESClient *sesClient = [[AmazonSESClient alloc] initWithAccessKey:ASES_ACCESS_KEY withSecretKey:ASES_SECRET_KEY];    
    SESListIdentitiesRequest *identiesRequest = [[SESListIdentitiesRequest alloc] init];

    SESListIdentitiesResponse *identitiesResponse = [sesClient listIdentities:identiesRequest];
    NSLog(@" identities count = %d",[identitiesResponse.identities count]);
    [identitiesResponse.identities enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        NSLog(@"identity:%@",[obj description]);
    }];

```
<a name="star2">*2 APIを利用したエンドポイントの取得と変更</a>

```objectivec
    AmazonSESClient *sesClient = [[AmazonSESClient alloc] initWithAccessKey:ASES_ACCESS_KEY withSecretKey:ASES_SECRET_KEY];
    
    NSLog(@"endpoint: %@" ,sesClient.endpoint);
    sesClient.endpoint = @"https://email.us-west-2.amazonaws.com";
    
```

ドキュメントをまだちゃんと読んでいないので、間違いあるかも。

以下リンク
[AMAZON SES公式blog](http://sesblog.amazon.com)
[AWS git](https://github.com/awslabs/aws-sdk-ios-samples)