Gmailに届かないCloudflare経由の独自ドメインメールを調べてみた

Cloudflareのメール転送機能(Email Routing)で、Gmailへの転送に失敗していたメールの調査を実施。 DKIM未設定のメールを Gmailが受取拒否していた事を確認しました。
2024.03.21

Cloudflare Email Routingを利用して、独自ドメインのメールアドレスを Gmail(@gmail)に転送している環境で、メール転送のエラー率上昇を確認。

Emailルーティンググラフ

その原因について、調査する機会がありましたので紹介させて頂きます。

転送設定

Cloudflare Email Routingを利用したメール転送を利用していました。

Gmailへのメール転送は、カスタムアドレスを設定して実施していました。

カスタムアドレス

ログ確認

アクティビティログより、エラー詳細の確認を試みました。

ActivityLog-Rejected

エラー応答は421。 以下の2パターンの拒否理由が確認できました。

レピュテーション不足(4.7.0)

Unknown error: transient error (421): 4.7.0 [104.30.8.180 19] Gmail has detected that this message is4.7.0 suspicious due to the very low reputation of the sending domain. To4.7.0 best protect our users from spam, the message has been blocked. For4.7.0 more information, go to4.7.0 https://support.google.com/mail/answer/188131 ll4-20020a170903090400b001e045e4134esi2162463plb.172 - gsmtp

SPFエラー(4.7.27)

Unknown error: transient error (421): 4.7.27 This mail has been rate limited because SPF does not pass. Gmail4.7.27 requires all large senders to authenticate with SPF.4.7.27 4.7.27 Authentication results:4.7.27 SPF [**.**] with ip: [104.30.8.196] = did not pass4.7.27 4.7.27 For instructions on setting up SPF authentication, go to4.7.27 https://support.google.com/a/answer/10685031 4.7.27 To learn more about Gmail's sender policy, go to4.7.27 https://support.google.com/mail/answer/81126. e189-20020a

メール認証情報の確認

Cloudflare経由で、Gmailへのメール送信に失敗したログの送信元メールアドレスから、送信元のECサイトを特定。 会員情報の変更時に送付される通知メールで、Cloudflare経由のGmail転送失敗が再現する事を確認。

会員情報として登録したメールアドレスを独自ドメインから

  • Gmail(@gmail)直接
  • Yahooメール (@ymail.jp)

に変更、ECサイトからの通知メールの受取を試みました。

Gmail

Gmailソース

Yahooメール

メール認証情報Yahooメール直

DKIM

転送メールでは受け取れないECサイトのメール、 Gmail、Yahooの直接配信であれば受け取る事は可能でしたが、 DMARC認証はSPF認証のみでパスしている状態でした。

独自ドメインのメールアドレスの転送先をYahooメールとした場合、メールは届きましたがDMARCはFAIL判定となる状態でした。

メール認証情報Yahooメール_Cloudflare経由

メールヘッダー確認

Yahooメールに届いたメールヘッダーを確認。

Cloudflareが付与したARCヘッダーに、DMARC認証、SPFのみでパスしている記録がありました。

ARC-Seal: i=1; a=rsa-sha256; s=2023; d=email.cloudflare.net; cv=none; b=cfy6ROwFPDG6lRSuazrrKceTdfxS9L5N4dCAAXCRC4PSXgBgSNl+JNGQdRTM1nak8/8/FeRoq R3XVVrAYKCvI1n9zNq+qjji1/TA5iDvTRgSY1KYLUHDvZYnNhji7UQr0HIr1O5wYcVcaICch1ur xAxc8As3a2/uXlMcHi8oVUO8vkncjqZXfCniWdb0iWsBDaeoUvpkoerTse79IM6Xv+SMjoa0DBC Ih3g8eR/Yu/oOUE3oSrEP5Knp6rZbZd2Gft+hnerl+9mnwBBARACL5WjPP1gDkwh0vWHL1CH1ec 2fn7DuCh+BQi4rbgaifIIAhdaFz8pj3BWOSsvSAnnNKg==;
ARC-Message-Signature: i=1; a=rsa-sha256; s=2023; d=email.cloudflare.net; c=relaxed/relaxed; h=Date:List-Unsubscribe:Reply-To:From:Subject:To:cc:resent-date :resent-from:resent-to:resent-cc:in-reply-to:references:list-id:list-help :list-subscribe:list-post:list-owner:list-archive; t=1711115046; x=1711719846; bh=u8Dsa3ECYFvgqNHRY4MZ/CuLikQU8xL4k6PQMG5kXaU=; b=HWSDzHMw+f fZ8ZobzxZFacWt/aSintO6tGfy1Un97PJNj9TS7jfri3Q4qrCcVGwyUn2t26Qt6ETP5RQb9hg3k Gk948NP5e56Y9s+vFH/sRZ+3wvQlRXybSwrz16XfD/JSV6h/fJsex/WhPMWEsaSgPZHlOQLT4EI BiJEuGAOXKrMBDEziYR0ZTncdQIKzz5E8ZjcgP2YBDDrbXk0SH40QQnahvp1iPv8uPnapdWyPyN /DyGAlYdcpURVkzqf02AsKjxPC2Dt3sDTNpoqAtIkhCzbTvhE7fze6nfgGexrliFATYf2jSaIR8 ZvcnGUrcCveXcIyBq23l5prxzZhVNBUQ==;
ARC-Authentication-Results: i=1; mx.cloudflare.net; dmarc=pass header.from=<略>.com policy.dmarc=none; spf=pass (mx.cloudflare.net: domain of postmaster@<略> designates <略> as permitted sender) smtp.helo=<略>; spf=pass (mx.cloudflare.net: domain of info@<略> designates <略> as permitted sender) smtp.mailfrom=info@<略>; arc=none smtp.remote-ip=<略>

暫定対処

Gmail以外のメール環境の用意

利用中のISPが提供するメールアドレス、DKIM、DMARC未設定のメールも受信可能である事を確認、 重要なメールについては、ISPのメールアドレスも併用する事としました。

複数の宛先への転送

Email Workers を利用したメール転送を利用して、転送先を複数のメールアドレスにする利用についても試みました。

メール転送のサンプル実装を参考に、複数のメールアドレスへ非同期に転送。

例外処理を追加、Gmailへの転送に失敗時、フェイルバック用に定義したメールアドレス宛に転送する事で、 メールを消失しない対策としました。

export default {
  async email(message, env, ctx) {
    if (!message) {
      console.warn("Warning: message is missing. Exiting.");
      return;
    }
    if (!message.from || typeof message.from !== 'string' || !message.from.includes('@')) {
      console.warn("Warning: message.from is not a valid email address. Exiting.");
      return;
    }

    const forwardToAddresses = ["<略>@gmail.com", "<略>@ymail.ne.jp"];
    const fallbackAddress = "<略>@<略>.jp";
    const successfulAddresses = [];

    const forwardPromises = forwardToAddresses.map(async (address) => {
      try {
        await message.forward(address);
        successfulAddresses.push(address);
      } catch (error) {
        // gmailへの転送に失敗したら、fallbackAddressへ転送
        if (address.includes("@gmail.com")) {
          console.warn("Warning:", error.message);
          try {
            await message.forward(fallbackAddress);
            successfulAddresses.push(fallbackAddress);
          } catch (fallbackError) {
            console.error(`Error forwarding email to fallback address (${fallbackAddress}):`, fallbackError);
            throw fallbackError; // エラー終了
          }
        } else {
          console.error(`Error forwarding email to ${address}:`, error);
          throw error; // エラー終了
        }
      }
    });

    try {
      await Promise.all(forwardPromises);
      console.log("Successful email forwarding to:", successfulAddresses.join(", "));
    } catch (error) {
      console.error("Error forwarding email:", error);
      throw error; // エラー終了
    }
  }
}

Email Workers ログサンプル

  • 転送成功
{
  "outcome": "ok",
  "scriptName": "fanout-gmail-yahoo",
  "diagnosticsChannelEvents": [],
  "exceptions": [],
  "logs": [
    {
      "message": [
        "Successful email forwarding to:",
        "<略>@gmail.com, <略>@ymail.ne.jp"
      ],
      "level": "log",
      "timestamp": 1711116588313
    }
  ],
  "eventTimestamp": 1711116578427,
  "event": {
    "rawSize": 5640,
    "rcptTo": "<略>@<略>.com",
    "mailFrom": "0106018e667eeabd-e8edf12e-c321-46ae-ab0e-4aee8ddccd6c-000000@<略>"
  },
  "id": 6
}
  • Gmail転送失敗
{
  "outcome": "ok",
  "scriptName": "fanout-gmail-yahoo",
  "diagnosticsChannelEvents": [],
  "exceptions": [],
  "logs": [
    {
      "message": [
        "Warning:",
        "could not send email: Unknown error: transient error (421): 4.7.0 [104.30.8.46      19] Gmail has detected that this message is4.7.0 suspicious due to the very low reputation of the sending domain. To4.7.0 best protect our users from spam, the message has been blocked. For4.7.0 more information, go to4.7.0  https://support.google.com/mail/answer/188131 fd25-20020a056a002e9900b006e72d056ae5si2037132pfb.276 - gsmtp"
      ],
      "level": "warn",
      "timestamp": 1711115627153
    },
    {
      "message": [
        "Successful email forwarding to:",
        "<略>@ymail.ne.jp, <略>@<略>.jp"
      ],
      "level": "log",
      "timestamp": 1711115632691
    }
  ],
  "eventTimestamp": 1711115620433,
  "event": {
    "rawSize": 4828,
    "rcptTo": "<略>@<略>.com",
    "mailFrom": "<略>@<略>"
  },
  "id": 5
}

Email Workers、現時点ではフリープラン、無課金で利用していますが、 実行時間の延長(10ms→30s)、詳細なログ記録、キューなどが利用可能となる有償プランについても検討したいと思います。

workersプラン

まとめ

Cloudflare Email Routing で発生した、Gmailへの転送が出来ないメールについて紹介させて頂きました。

SPF認証のみ、DKMI認証なしでDMARC認証を通過したメール、中継時に適切なARCヘッダーが付与されている場合でも、 転送先のGmailにより SPAMと判定されやすい状況が確認されました。

今回の事象を確認した Cloudflare に限らず、 独自ドメインをサポートするメール転送サービスを利用して、 Gmailのメールアドレスに転送している利用では類似の事象が生じやすくなっている可能性があります。

Gmailへの転送時にメールが遮断されてしまう可能性に備え、複数のメールアドレスを併用したり、 独自ドメインをサポートするメールサービスが、転送だけでなくメールボックスの利用が可能な場合には、 中継したメールを中継環境に一定期間保持するなどの対策を講じる事をおすすめします。