AMP

AMP 邮件中的 CORS

重要提示:本文档不适用于您当前选择的格式网站

跨域资源共享(CORS)是一种使用 HTTP 标头告诉浏览器哪些来源可以使用 XHR 访问资源的机制。AMP 邮件扩展了此机制,增加了 HTTP 标头,类似地告诉电子邮件客户端哪些发送者可以访问这些资源。

目前有两种版本的此机制。目前,建议在服务器端同时支持这两种版本。

版本 2

当电子邮件通过 amp-formamp-list 或任何其他基于 XHR 的机制发出请求时,电子邮件客户端会包含以下 HTTP 标头

  • AMP-Email-Sender,设置为电子邮件发送者的电子邮件地址。

它期望 HTTP 响应返回以下标头

  • AMP-Email-Allow-Sender,其值与请求中的 AMP-Email-Sender 相同,或者为 *,表示允许所有发送者电子邮件。

示例

用户通过访问 https://emailclient.example/myinbox 在其电子邮件客户端中打开来自 sender@company.example 的电子邮件。该电子邮件使用 AMP 邮件,并使用 amp-listhttps://company.example/data.json 加载数据。

电子邮件客户端向 https://company.example/data.json 发送 HTTP 请求,并设置以下标头

AMP-Email-Sender: sender@company.example

电子邮件客户端期望 HTTP 响应包含以下标头

AMP-Email-Allow-Sender: sender@company.example

或者,允许在任一标头中使用 *(但不建议)。

版本 1(已弃用)

在版本 1 中,电子邮件客户端使用查询字符串参数而不是 HTTP 标头来指示发送者的电子邮件。它还提供 Origin 标头,并要求响应中包含 Access-Control-Allow-Origin 标头,类似于网站上的 CORS。

当电子邮件通过 amp-formamp-list 或任何其他基于 XHR 的机制发出请求时,电子邮件客户端会包含以下 HTTP 标头

  • Origin,其值为用于显示电子邮件的页面的来源。

URL 也始终具有一个查询字符串,其中 __amp_source_origin 参数设置为电子邮件发送者的电子邮件地址。

它期望 HTTP 响应包含以下标头

  • Access-Control-Allow-Origin,其值与请求中的 Origin 相同
  • AMP-Access-Control-Allow-Source-Origin,其值与请求中的 __amp_source_origin 查询字符串参数相同。
  • Access-Control-Expose-Headers,设置为 AMP-Access-Control-Allow-Source-Origin

示例

用户通过访问 https://emailclient.example/myinbox 在其电子邮件客户端中打开来自 sender@company.example 的电子邮件。该电子邮件使用 AMP 邮件,并使用 amp-listhttps://company.example/data.json 加载数据。

电子邮件客户端向 https://company.example/data.json?__amp_source_origin=sender@company.example 发送 HTTP 请求(请注意添加的查询字符串),并设置以下标头

Origin: https://emailclient.example

电子邮件客户端期望 HTTP 响应包含以下标头

Access-Control-Allow-Origin: https://emailclient.example
AMP-Access-Control-Allow-Source-Origin: sender@company.example
Access-Control-Expose-Headers: AMP-Access-Control-Allow-Source-Origin

请注意,此版本不支持在 AMP-Access-Control-Allow-Source-Origin 标头中使用 *

实施 CORS

以下是在服务器端实施 CORS 的建议步骤,该 CORS 支持版本 1 和版本 2

当您收到 HTTP 请求时,请检查是否设置了 OriginAMP-Email-Sender HTTP 标头。

  1. 如果设置了 AMP-Email-Sender 标头
    1. senderEmailAMP-Email-Sender 标头的值。
    2. 检查 senderEmail 是否是您拥有的或您信任的电子邮件地址。如果不是,则拒绝请求。
    3. 将响应标头 AMP-Email-Allow-Sender 设置为 senderEmail
  2. 如果设置了 Origin 标头,但未设置 AMP-Email-Sender
    1. requestOriginOrigin 标头的值。
    2. 将响应标头 Access-Control-Allow-Origin 设置为 requestOrigin
    3. 检查 URL 是否包含 __amp_source_origin 查询字符串参数。如果不是,则拒绝请求。
    4. senderEmail__amp_source_origin 查询字符串参数的值。
    5. 检查 senderEmail 是否是您拥有的或您信任的电子邮件地址。如果不是,则拒绝请求。
    6. 将响应标头 AMP-Access-Control-Allow-Source-Origin 设置为 senderEmail
    7. 将响应标头 Access-Control-Expose-Headers 设置为 AMP-Access-Control-Allow-Source-Origin
  3. 如果既未设置 Origin 也未设置 AMP-Email-Sender,则拒绝请求。

示例 1

电子邮件客户端发送的请求

GET /data.json?__amp_source_origin=sender@company.example HTTP/1.1
Host: company.example
Origin: https://emailclient.example
User-Agent: EmailClientProxy
Accept: application/json

期望的响应头

Access-Control-Allow-Origin: https://emailclient.example
Access-Control-Expose-Headers: AMP-Access-Control-Allow-Source-Origin
AMP-Access-Control-Allow-Source-Origin: sender@company.example

解释

由于设置了 Origin 标头,因此此请求正在使用 CORS 版本 1,并且需要设置上面列出的三个标头。

示例 2

电子邮件客户端发送的请求

GET /data.json HTTP/1.1
Host: company.example
AMP-Email-Sender: sender@company.example
User-Agent: EmailClientProxy
Accept: application/json

期望的响应头

AMP-Email-Allow-Sender: sender@company.example

解释

由于设置了 AMP-Email-Sender 标头,因此此请求正在使用 CORS 版本 2,并且只需要 AMP-Email-Allow-Sender 标头。

示例 3

电子邮件客户端发送的请求

GET /data.json?__amp_source_origin=sender@company.example HTTP/1.1
Host: company.example
Origin: https://emailclient.example
AMP-Email-Sender: sender@company.example
User-Agent: EmailClientProxy
Accept: application/json

期望的响应头

AMP-Email-Allow-Sender: sender@company.example

解释

同时设置了 OriginAMP-Email-Sender,表明客户端支持这两个版本。由于版本 2 优先,因此仅设置 AMP-Email-Allow-Sender 标头,并且可以安全地忽略 Origin__amp_source_origin 的值。

代码示例

PHP

if (isset($_SERVER['HTTP_AMP_EMAIL_SENDER'])) {
    $senderEmail = $_SERVER['HTTP_AMP_EMAIL_SENDER'];
    if (!isAllowedSender($senderEmail)) {
        die('invalid sender');
    }
    header("AMP-Email-Allow-Sender: $senderEmail");
} elseif (isset($_SERVER['HTTP_ORIGIN'])) {
    $requestOrigin = $_SERVER['HTTP_ORIGIN'];
    if (empty($_GET['__amp_source_origin'])) {
        die('invalid request');
    }
    $senderEmail = $_GET['__amp_source_origin'];
    if (!isAllowedSender($senderEmail)) {
        die('invalid sender');
    }
    header("Access-Control-Allow-Origin: $requestOrigin");
    header('Access-Control-Expose-Headers: AMP-Access-Control-Allow-Source-Origin');
    header("AMP-Access-Control-Allow-Source-Origin: $senderEmail");
} else {
    die('invalid request');
}

Python (Django)

response = JsonResponse(...)
if request.META.HTTP_AMP_EMAIL_SENDER:
    senderEmail = request.META.HTTP_AMP_EMAIL_SENDER
    if not isAllowedSender(senderEmail):
        raise PermissionDenied
    response['AMP-Email-Allow-Sender'] = senderEmail
elif request.META.HTTP_ORIGIN:
    requestOrigin = request.META.HTTP_ORIGIN
    senderEmail = request.GET.get('__amp_source_origin')
    if not isAllowedSender(senderEmail):
        raise PermissionDenied
    response['Access-Control-Allow-Origin'] = requestOrigin
    response['Access-Control-Expose-Headers'] = 'AMP-Access-Control-Allow-Source-Origin'
    response['AMP-Access-Control-Allow-Source-Origin'] = senderEmail
else
    raise PermissionDenied

SSJS

<script runat="server" language="JavaScript">

Platform.Load("core", "1");

if (Platform.Request.GetRequestHeader("AMP-Email-Sender")) {
  var senderEmail = Platform.Request.GetRequestHeader("AMP-Email-Sender")
  if (isValidSender(senderEmail)) {
    HTTPHeader.SetValue("AMP-Email-Allow-Sender", senderEmail)
  } else {
    Platform.Function.RaiseError("Sender Not Allowed",true,"statusCode","3");
  }
} else if (Platform.Request.GetRequestHeader("Origin")) {
  var requestOrigin = Platform.Request.GetRequestHeader("Origin")

  if (Platform.Request.GetQueryStringParameter("__amp_source_origin")) {
    var senderEmail = Platform.Request.GetQueryStringParameter("__amp_source_origin");

    if (isValidSender(senderEmail)) {
      HTTPHeader.SetValue("Access-Control-Allow-Origin", requestOrigin);
      HTTPHeader.SetValue("Access-Control-Expose-Headers", "AMP-Access-Control-Allow-Source-Origin");
      HTTPHeader.SetValue("AMP-Access-Control-Allow-Source-Origin", senderEmail);
    } else {
      Platform.Function.RaiseError("Invalid Source Origin",true,"statusCode","3");
    }

  } else {
    Platform.Function.RaiseError("Source Origin Not Present",true,"statusCode","3");
  }
} else {
  Platform.Function.RaiseError("Origin and Sender Not Present",true,"statusCode","3");
}
</script>

请访问Salesforce 开发人员文档,了解有关 SSJS 的更多信息。

Node.js

使用官方支持的 @ampproject/toolbox-cors npm 包