Amazon Pinpointから送信するメールの送信者名にマルチバイト文字を指定する方法

エンコードは大事 ちなみに、のんピの"ピ"はカタカナです。
2022.08.23

マルチバイト文字を文字化けせずに表示させたい

こんにちは、のんピ(@non____97)です。

皆さんはAmazon Pinpointから送信したメールの送信者名にマルチバイト文字を表示したいなと思ったことはありますか? 私はあります。

Amazon Pinpointから送信したメールの送信者名を自分で設定する場合はAmazon Pinpointのコンソールからすべてのプロジェクト-プロジェクト名-設定-Eメール-Eメールの編集わかりやすい送信者名 で行えます。

マネジメントコンソール上の わかりやすい送信者名 の説明を確認すると以下のように記載がありました。

わかりやすい送信者名は、受取人の E メールクライアントでメッセージを送信するときに表示される名前です。この名前は、E メールの送信に使用する E メールアドレスとは異なります。E メールのソースコード

では、送信者のアドレスは通常、次の例に似ています。

Mary Major

この例では、Mary Major はわかりやすい送信者名、「mary@example.com」は送信者の実際の E メールアドレスです。 わかりやすい送信者名は最大で 25 文字までとするのがベストとされています。多くの E メールクライアントでは、25 文字を超えるわかりやすい送信者名は切り捨てられます。

分かりやすい送信者名には英数字および ! @ # $ % & * ( ) - + : ; = . , _ ? / の記号のみを使用できます。また、; @、[] などの記号は、二重引用符で囲まれた場合にのみ使用できます。

英数字と一部記号しか使えないようですね。

試しにマルチバイト文字を設定してみました。

わかりやすい送信者名にマルチバイト文字を入力

この状態でキャンペーンを作成してメール送信してみます。

キャンペーンを起動

受信したメールを確認すると、文字化けしてしまっています。

文字化け

これは困った

ということでメールの送信者名にマルチバイト文字を表示させてみます。

いきなりまとめ

  • 送信者名をMIMEエンコードしよう
  • AWS CLIやAWS SDKからなら、任意のメールアドレスに任意の送信者名を設定することが可能
  • マネジメントコンソールで設定できる送信者名はエンコード後で66文字以内
  • AWS CLIやAWS SDKからなら66文字以上の送信者名も指定できる
    • あまりにも長すぎるとメールクライアントで送信者名が表示されないので注意

答え : MIMEエンコードをする

以下記事にはAmazon SESではマルチバイトの送信者名を文字化けせずに表示するために、RFC 822 / RFC 2047でエンコードされたアドレスに変換しています。

Amazon Pinpointのメール送信はAmazon SESの機能を使用しています。

そこで、Amazon SESのドキュメントを確認すると以下のような記載がありました。

MIME エンコード

古いシステムとの互換性を維持するために、Amazon SES は RFC 2821で定義されている SMTP の 7 ビット ASCII 制限を優先します。非 ASCII 文字を含むコンテンツを送信する場合は、これらの文字を 7 ビット ASCII 文字を使用する形式にエンコードする必要があります。

E メールヘッダー

メッセージヘッダーをエンコードするには、MIME encoded-word 構文を使用します。MIME encoded word 構文では、次の形式が使用されます。

  =?charset?encoding?encoded-text?=

Amazon SES API を使用して raw E メールを送信する - Amazon Simple Email Service

要するマルチバイト文字 = 非 ASCII 文字を含むのであれば、=?charset?encoding?encoded-text?=という形式にMIMEエンコードしろということですね。

エンコード方法はQエンコードとBase64エンコードがあります。今回はBase64エンコードにしてみましょう。

エンコードはPythonのemail.headerを使うと簡単です。

実際にやってみます。

# Pythonの起動
> python
Python 3.10.6 (main, Aug 22 2022, 19:05:02) [Clang 13.1.6 (clang-1316.0.21.2.5)] on darwin
Type "help", "copyright", "credits" or "license" for more information.

# email.headerのインポート
>>> from email.header import Header

# エンコード
>>> Header('のんピ').encode()
'=?utf-8?b?44Gu44KT44OU?='

のんピという文字列がエンコードされて=?utf-8?b?44Gu44KT44OU?=という文字列が出力されました。

こちらの文字列をAmazon Pinpointのコンソールからすべてのプロジェクト-プロジェクト名-設定-Eメール-Eメールの編集から わかりやすい送信者名 に設定します。

わかりやすい送信者名をエンコードした文字列に変更

この状態でキャンペーンを作成してメール送信してみます。

わかりやすい送信者名をエンコードした文字列に設定してキャンペーンを作成

送信者名が文字化けすることなく受信できました。

文字化けせずに受信

デフォルトの送信者アドレス以外でメール送信する場合も送信者名を指定したい

送信者名を文字化けすることなく送信することができました。

ただし、マネジメントコンソール上では送信者名を指定できるのはデフォルトの送信者アドレスを選択した場合のみです。

わかりやすい送信者名は、デフォルトの送信者の E メールアドレスでのみ使用できます

この状態でメールを送信しても送信者名は設定されていません。

送信者名が指定されていない

これは地味に困ります。

回避策はAWS CLIやAWS SDKでメールアドレスと送信者名を直接指定することが挙げられます。

Amazon PinpointのCampaigns APIのPOST schemaを確認すると、以下のように定義されています。

{
  "TreatmentName": "string",
  "TreatmentDescription": "string",
  "MessageConfiguration": {
    "DefaultMessage": {
      "Body": "string",
      "Title": "string",
      "ImageUrl": "string",
      "ImageIconUrl": "string",
      "ImageSmallIconUrl": "string",
      "MediaUrl": "string",
      "Action": enum,
      "Url": "string",
      "SilentPush": boolean,
      "JsonBody": "string",
      "RawContent": "string",
      "TimeToLive": integer
    },
    "APNSMessage": {
      "Body": "string",
      "Title": "string",
      "ImageUrl": "string",
      "ImageIconUrl": "string",
      "ImageSmallIconUrl": "string",
      "MediaUrl": "string",
      "Action": enum,
      "Url": "string",
      "SilentPush": boolean,
      "JsonBody": "string",
      "RawContent": "string",
      "TimeToLive": integer
    },
    "GCMMessage": {
      "Body": "string",
      "Title": "string",
      "ImageUrl": "string",
      "ImageIconUrl": "string",
      "ImageSmallIconUrl": "string",
      "MediaUrl": "string",
      "Action": enum,
      "Url": "string",
      "SilentPush": boolean,
      "JsonBody": "string",
      "RawContent": "string",
      "TimeToLive": integer
    },
    "ADMMessage": {
      "Body": "string",
      "Title": "string",
      "ImageUrl": "string",
      "ImageIconUrl": "string",
      "ImageSmallIconUrl": "string",
      "MediaUrl": "string",
      "Action": enum,
      "Url": "string",
      "SilentPush": boolean,
      "JsonBody": "string",
      "RawContent": "string",
      "TimeToLive": integer
    },
    "BaiduMessage": {
      "Body": "string",
      "Title": "string",
      "ImageUrl": "string",
      "ImageIconUrl": "string",
      "ImageSmallIconUrl": "string",
      "MediaUrl": "string",
      "Action": enum,
      "Url": "string",
      "SilentPush": boolean,
      "JsonBody": "string",
      "RawContent": "string",
      "TimeToLive": integer
    },
    "EmailMessage": {
      "Body": "string",
      "Title": "string",
      "HtmlBody": "string",
      "FromAddress": "string"
    },
    "SMSMessage": {
      "Body": "string",
      "MessageType": enum,
      "SenderId": "string",
      "OriginationNumber": "string",
      "EntityId": "string",
      "TemplateId": "string"
    },
    "CustomMessage": {
      "Data": "string"
    },
    "InAppMessage": {
      "Body": "string",
      "Layout": enum,
      "Content": [
        {
          "HeaderConfig": {
            "Header": "string",
            "TextColor": "string",
            "Alignment": enum
          },
          "BackgroundColor": "string",
          "BodyConfig": {
            "Body": "string",
            "TextColor": "string",
            "Alignment": enum
          },
          "ImageUrl": "string",
          "PrimaryBtn": {
            "DefaultConfig": {
              "Text": "string",
              "ButtonAction": enum,
              "Link": "string",
              "TextColor": "string",
              "BackgroundColor": "string",
              "BorderRadius": integer
            },
            "Web": {
              "ButtonAction": enum,
              "Link": "string"
            },
            "IOS": {
              "ButtonAction": enum,
              "Link": "string"
            },
            "Android": {
              "ButtonAction": enum,
              "Link": "string"
            }
          },
          "SecondaryBtn": {
            "DefaultConfig": {
              "Text": "string",
              "ButtonAction": enum,
              "Link": "string",
              "TextColor": "string",
              "BackgroundColor": "string",
              "BorderRadius": integer
            },
            "Web": {
              "ButtonAction": enum,
              "Link": "string"
            },
            "IOS": {
              "ButtonAction": enum,
              "Link": "string"
            },
            "Android": {
              "ButtonAction": enum,
              "Link": "string"
            }
          }
        }
      ],
      "CustomConfig": {
      }
    }
  },
  "Schedule": {
    "StartTime": "string",
    "EndTime": "string",
    "Frequency": enum,
    "IsLocalTime": boolean,
    "Timezone": "string",
    "QuietTime": {
      "Start": "string",
      "End": "string"
    },
    "EventFilter": {
      "Dimensions": {
        "EventType": {
          "DimensionType": enum,
          "Values": [
            "string"
          ]
        },
        "Attributes": {
        },
        "Metrics": {
        }
      },
      "FilterType": enum
    }
  },
  "TemplateConfiguration": {
    "SMSTemplate": {
      "Name": "string",
      "Version": "string"
    },
    "EmailTemplate": {
      "Name": "string",
      "Version": "string"
    },
    "PushTemplate": {
      "Name": "string",
      "Version": "string"
    },
    "VoiceTemplate": {
      "Name": "string",
      "Version": "string"
    }
  },
  "CustomDeliveryConfiguration": {
    "EndpointTypes": [
      enum
    ],
    "DeliveryUri": "string"
  },
  "SegmentId": "string",
  "SegmentVersion": integer,
  "IsPaused": boolean,
  "AdditionalTreatments": [
    {
      "TreatmentName": "string",
      "TreatmentDescription": "string",
      "MessageConfiguration": {
        "DefaultMessage": {
          "Body": "string",
          "Title": "string",
          "ImageUrl": "string",
          "ImageIconUrl": "string",
          "ImageSmallIconUrl": "string",
          "MediaUrl": "string",
          "Action": enum,
          "Url": "string",
          "SilentPush": boolean,
          "JsonBody": "string",
          "RawContent": "string",
          "TimeToLive": integer
        },
        "APNSMessage": {
          "Body": "string",
          "Title": "string",
          "ImageUrl": "string",
          "ImageIconUrl": "string",
          "ImageSmallIconUrl": "string",
          "MediaUrl": "string",
          "Action": enum,
          "Url": "string",
          "SilentPush": boolean,
          "JsonBody": "string",
          "RawContent": "string",
          "TimeToLive": integer
        },
        "GCMMessage": {
          "Body": "string",
          "Title": "string",
          "ImageUrl": "string",
          "ImageIconUrl": "string",
          "ImageSmallIconUrl": "string",
          "MediaUrl": "string",
          "Action": enum,
          "Url": "string",
          "SilentPush": boolean,
          "JsonBody": "string",
          "RawContent": "string",
          "TimeToLive": integer
        },
        "ADMMessage": {
          "Body": "string",
          "Title": "string",
          "ImageUrl": "string",
          "ImageIconUrl": "string",
          "ImageSmallIconUrl": "string",
          "MediaUrl": "string",
          "Action": enum,
          "Url": "string",
          "SilentPush": boolean,
          "JsonBody": "string",
          "RawContent": "string",
          "TimeToLive": integer
        },
        "BaiduMessage": {
          "Body": "string",
          "Title": "string",
          "ImageUrl": "string",
          "ImageIconUrl": "string",
          "ImageSmallIconUrl": "string",
          "MediaUrl": "string",
          "Action": enum,
          "Url": "string",
          "SilentPush": boolean,
          "JsonBody": "string",
          "RawContent": "string",
          "TimeToLive": integer
        },
        "EmailMessage": {
          "Body": "string",
          "Title": "string",
          "HtmlBody": "string",
          "FromAddress": "string"
        },
        "SMSMessage": {
          "Body": "string",
          "MessageType": enum,
          "SenderId": "string",
          "OriginationNumber": "string",
          "EntityId": "string",
          "TemplateId": "string"
        },
        "CustomMessage": {
          "Data": "string"
        },
        "InAppMessage": {
          "Body": "string",
          "Layout": enum,
          "Content": [
            {
              "HeaderConfig": {
                "Header": "string",
                "TextColor": "string",
                "Alignment": enum
              },
              "BackgroundColor": "string",
              "BodyConfig": {
                "Body": "string",
                "TextColor": "string",
                "Alignment": enum
              },
              "ImageUrl": "string",
              "PrimaryBtn": {
                "DefaultConfig": {
                  "Text": "string",
                  "ButtonAction": enum,
                  "Link": "string",
                  "TextColor": "string",
                  "BackgroundColor": "string",
                  "BorderRadius": integer
                },
                "Web": {
                  "ButtonAction": enum,
                  "Link": "string"
                },
                "IOS": {
                  "ButtonAction": enum,
                  "Link": "string"
                },
                "Android": {
                  "ButtonAction": enum,
                  "Link": "string"
                }
              },
              "SecondaryBtn": {
                "DefaultConfig": {
                  "Text": "string",
                  "ButtonAction": enum,
                  "Link": "string",
                  "TextColor": "string",
                  "BackgroundColor": "string",
                  "BorderRadius": integer
                },
                "Web": {
                  "ButtonAction": enum,
                  "Link": "string"
                },
                "IOS": {
                  "ButtonAction": enum,
                  "Link": "string"
                },
                "Android": {
                  "ButtonAction": enum,
                  "Link": "string"
                }
              }
            }
          ],
          "CustomConfig": {
          }
        }
      },
      "Schedule": {
        "StartTime": "string",
        "EndTime": "string",
        "Frequency": enum,
        "IsLocalTime": boolean,
        "Timezone": "string",
        "QuietTime": {
          "Start": "string",
          "End": "string"
        },
        "EventFilter": {
          "Dimensions": {
            "EventType": {
              "DimensionType": enum,
              "Values": [
                "string"
              ]
            },
            "Attributes": {
            },
            "Metrics": {
            }
          },
          "FilterType": enum
        }
      },
      "TemplateConfiguration": {
        "SMSTemplate": {
          "Name": "string",
          "Version": "string"
        },
        "EmailTemplate": {
          "Name": "string",
          "Version": "string"
        },
        "PushTemplate": {
          "Name": "string",
          "Version": "string"
        },
        "VoiceTemplate": {
          "Name": "string",
          "Version": "string"
        }
      },
      "CustomDeliveryConfiguration": {
        "EndpointTypes": [
          enum
        ],
        "DeliveryUri": "string"
      },
      "SizePercent": integer
    }
  ],
  "HoldoutPercent": integer,
  "Limits": {
    "Daily": integer,
    "Total": integer,
    "Session": integer,
    "MessagesPerSecond": integer,
    "MaximumDuration": integer
  },
  "Name": "string",
  "Hook": {
    "LambdaFunctionName": "string",
    "WebUrl": "string",
    "Mode": enum
  },
  "Description": "string",
  "tags": {
  },
  "Priority": integer
}

EmailMessageにStringでFromAddressがあるではありませんか。

送信者名のプロパティがないので、FromAddressに送信者名を一緒に指定してあげれば良さそうです。

今回はAWS CLIのcreate-campaignでキャンペーンを作成してメール送信をしてみます。

せっかくなので送信者名も変更します。

>>> Header('のんピの"ピ"はカタカナです。').encode()
'=?utf-8?b?44Gu44KT44OU44GuIuODlCLjga/jgqvjgr/jgqvjg4rjgafjgZnjgII=?='

のんピの"ピ"はカタカナです。をエンコードすると=?utf-8?b?44Gu44KT44OU44GuIuODlCLjga/jgqvjgr/jgqvjg4rjgafjgZnjgII=?=になるようです。こちらの文字列をメールアドレスと一緒にFromAddressに指定します。

エンコードした文字列をパラメーターとして指定します。

# キャンペーンのパラメーターを指定
$ application_id=ff6c2a0583624d2687c4d868b30ffcae
$ campaign_name=mail-test
$ segment_id=a2429a7271434bc58bc944f6a847c941
$ email_template_name=test
$ from_address='=?utf-8?b?44Gu44KT44OU44GuIuODlCLjga/jgqvjgr/jgqvjg4rjgafjgZnjgII=?= <pinpoint-mail@non-97.net>'

$ create_campaign_input=$(cat <<EOM
{
    "ApplicationId": "$application_id",
    "WriteCampaignRequest": {
      "Name": "$campaign_name",
      "Schedule": {
        "StartTime": "IMMEDIATE"
      },
      "SegmentId": "$segment_id",
      "SegmentVersion": 1,
      "TemplateConfiguration": {
        "EmailTemplate": {
          "Name": "$email_template_name"
        }
      },
      "MessageConfiguration": {
        "EmailMessage": {
          "FromAddress": "$from_address"
        }
      }
    }
}
EOM
)

# キャンペーンの作成
$ aws pinpoint create-campaign \
    --cli-input-json "$create_campaign_input"
{
    "CampaignResponse": {
        "ApplicationId": "ff6c2a0583624d2687c4d868b30ffcae",
        "Arn": "arn:aws:mobiletargeting:us-east-1:<AWSアカウントID>:apps/ff6c2a0583624d2687c4d868b30ffcae/campaigns/e8fcc6e2b5bd4d32ac7b812d18f75477",
        "CreationDate": "2022-08-23T00:48:13.244Z",
        "Description": " ",
        "Id": "e8fcc6e2b5bd4d32ac7b812d18f75477",
        "IsPaused": false,
        "LastModifiedDate": "2022-08-23T00:48:13.244Z",
        "MessageConfiguration": {
            "EmailMessage": {
                "FromAddress": "=?utf-8?b?44Gu44KT44OU44GuIuODlCLjga/jgqvjgr/jgqvjg4rjgafjgZnjgII=?= <pinpoint-mail@non-97.net>"
            }
        },
        "Name": "mail-test",
        "Schedule": {
            "StartTime": "IMMEDIATE"
        },
        "SegmentId": "a2429a7271434bc58bc944f6a847c941",
        "SegmentVersion": 1,
        "State": {
            "CampaignStatus": "SCHEDULED"
        },
        "tags": {},
        "TemplateConfiguration": {
            "EmailTemplate": {
                "Name": "test"
            }
        },
        "Version": 1
    }
}

キャンペーン作成後、メールの受信ボックスを確認すると、デフォルトの送信者アドレスpinpoint@non-97.netと異なるアドレスpinpoint-mail@non-97.netで送信者名のんピの"ピ"はカタカナです。のメールを受信できていました。

任意の送信者名を指定できることを確認

送信者名に長い文字列を指定するとどうなるか

送信者名に長い文字列を指定するとどうなるかも確認してみます。

例としてのんピだああああああああ!!!!を送信者名にしてみます。

こちらの文字列をエンコードします。

>>> Header('のんピだああああああああ!!!!').encode()
'=?utf-8?b?44Gu44KT44OU44Gg44GC44GC44GC44GC44GC44GC44GC44GC77yB77yB77yB77yB?='

エンコードした文字列をマネジメントコンソールから わかりやすい送信者名 に指定して保存しようとすると、最大66文字しか入力できないと怒られてしまいました。

わかりやすい送信者名には、最大 66 文字まで含めることができます

AWS CLIの場合は指定できるか試してみましょう。

# キャンペーンのパラメーターを指定
$ application_id=ff6c2a0583624d2687c4d868b30ffcae
$ campaign_name=mail-test
$ segment_id=a2429a7271434bc58bc944f6a847c941
$ email_template_name=test
$ from_address='=?utf-8?b?44Gu44KT44OU44Gg44GC44GC44GC44GC44GC44GC44GC44GC77yB77yB77yB77yB?= <pinpoint-long-sender-name@non-97.net>'

$ create_campaign_input=$(cat <<EOM
{
    "ApplicationId": "$application_id",
    "WriteCampaignRequest": {
      "Name": "$campaign_name",
      "Schedule": {
        "StartTime": "IMMEDIATE"
      },
      "SegmentId": "$segment_id",
      "SegmentVersion": 1,
      "TemplateConfiguration": {
        "EmailTemplate": {
          "Name": "$email_template_name"
        }
      },
      "MessageConfiguration": {
        "EmailMessage": {
          "FromAddress": "$from_address"
        }
      }
    }
}
EOM
)

# キャンペーンの作成
aws pinpoint create-campaign \
    --cli-input-json "$create_campaign_input"
{
    "CampaignResponse": {
        "ApplicationId": "ff6c2a0583624d2687c4d868b30ffcae",
        "Arn": "arn:aws:mobiletargeting:us-east-1:<AWSアカウントID>:apps/ff6c2a0583624d2687c4d868b30ffcae/campaigns/46d4b1d7774a406187318beddba5a0d9",
        "CreationDate": "2022-08-23T02:11:32.112Z",
        "Description": " ",
        "Id": "46d4b1d7774a406187318beddba5a0d9",
        "IsPaused": false,
        "LastModifiedDate": "2022-08-23T02:11:32.112Z",
        "MessageConfiguration": {
            "EmailMessage": {
                "FromAddress": "=?utf-8?b?44Gu44KT44OU44Gg44GC44GC44GC44GC44GC44GC44GC44GC77yB77yB77yB77yB?= <pinpoint-long-sender-name@non-97.net>"
            }
        },
        "Name": "mail-test",
        "Schedule": {
            "StartTime": "IMMEDIATE"
        },
        "SegmentId": "a2429a7271434bc58bc944f6a847c941",
        "SegmentVersion": 1,
        "State": {
            "CampaignStatus": "SCHEDULED"
        },
        "tags": {},
        "TemplateConfiguration": {
            "EmailTemplate": {
                "Name": "test"
            }
        },
        "Version": 1
    }
}

キャンペーン作成後、メールの受信ボックスを確認すると、指定した送信者名のメールを受信できていました。

長い送信者名を正しく表示できることを確認

もっと長い送信者名はどうでしょうか。のんピです。Amazon Pinpointで長い送信者名を指定できるか検証しています。と44文字の文字列を送信者名に指定してみます。

>>> Header('のんピです。Amazon Pinpointで長い送信者名を指定できるか検証しています。').encode()
'=?utf-8?b?44Gu44KT44OU44Gn44GZ44CCQW1hem9uIFBpbnBvaW5044Gn6ZW344GE6YCB5L+h?=\n =?utf-8?b?6ICF5ZCN44KS5oyH5a6a44Gn44GN44KL44GL5qSc6Ki844GX44Gm44GE44G+44GZ?=\n =?utf-8?b?44CC?='

エンコードすると長すぎて途中に改行が2回入ってますね。

こちらの文字列を送信者名に指定してキャンペーンを作成し、メールを送信します。

受信ボックスを確認すると、送信者名が表示されていません。悲しい。

送信者名が表示されない

メールのソースを確認すると、設定した送信者名が表示されました。表示されるかどうかはメールクライアントの仕様次第ですかね。

メールのソース

エンコードは大事

Amazon Pinpointから送信したメールの送信者名にマルチバイト文字を表示する方法を紹介しました。

マルチバイト文字を使おうとすると思わぬトラップに引っかかることがあるので、気をつけていきたいですね。

ちなみに、のんピの"ピ"はカタカナです。のんぴではありません。

この記事が誰かの助けになれば幸いです。

以上、AWS事業本部 コンサルティング部の のんピ(@non____97)でした!