
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
    <channel>
        <title><![CDATA[ The Cloudflare Blog ]]></title>
        <description><![CDATA[ Get the latest news on how products at Cloudflare are built, technologies used, and join the teams helping to build a better Internet. ]]></description>
        <link>https://blog.cloudflare.com</link>
        <atom:link href="https://blog.cloudflare.com/" rel="self" type="application/rss+xml"/>
        <language>en-us</language>
        <image>
            <url>https://blog.cloudflare.com/favicon.png</url>
            <title>The Cloudflare Blog</title>
            <link>https://blog.cloudflare.com</link>
        </image>
        <lastBuildDate>Sat, 04 Apr 2026 13:54:54 GMT</lastBuildDate>
        <item>
            <title><![CDATA[Make Your Website Conversational for People and Agents with NLWeb and AutoRAG]]></title>
            <link>https://blog.cloudflare.com/conversational-search-with-nlweb-and-autorag/</link>
            <pubDate>Thu, 28 Aug 2025 14:00:00 GMT</pubDate>
            <description><![CDATA[ With NLWeb, an open project by Microsoft, and Cloudflare AutoRAG, conversational search is now a one-click setup for your website. ]]></description>
            <content:encoded><![CDATA[ <p>Publishers and content creators have historically relied on traditional keyword-based search to help users navigate their website’s content. However, traditional search is built on outdated assumptions: users type in keywords to indicate intent, and the site returns a list of links for the most relevant results. It’s up to the visitor to click around, skim pages, and piece together the answer they’re looking for. </p><p><a href="https://www.cloudflare.com/learning/ai/what-is-artificial-intelligence/"><u>AI</u></a> has reset expectations and that paradigm is breaking: how we search for information has fundamentally changed.</p>
    <div>
      <h2>Your New Type of Visitors</h2>
      <a href="#your-new-type-of-visitors">
        
      </a>
    </div>
    <p>Users no longer want to search websites the old way. They’re used to interacting with AI systems like Copilot, Claude, and ChatGPT, where they can simply ask a question and get an answer. We’ve moved from search engines to answer engines. </p><p>At the same time, websites now have a new class of visitors, AI agents. Agents face the same pain with keyword search: they have to issue keyword queries, click through links, and scrape pages to piece together answers. But they also need more: a structured way to ask questions and get reliable answers across websites. This means that websites need a way to give the agents they trust controlled access, so that information is retrieved accurately.</p><p>Website owners need a way to participate in this shift.</p>
    <div>
      <h2>A New Search Model for the Agentic Web</h2>
      <a href="#a-new-search-model-for-the-agentic-web">
        
      </a>
    </div>
    <p>If AI has reset expectations, what comes next? To meet both people and agents where they are, websites need more than incremental upgrades to keyword search. They need a model that makes conversational access to content a first-class part of the web itself.</p><p>That’s what we want to deliver: combining an open standard (NLWeb) with the infrastructure (AutoRAG) to make it simple for any website to become AI-ready.</p><p><a href="https://news.microsoft.com/source/features/company-news/introducing-nlweb-bringing-conversational-interfaces-directly-to-the-web/"><u>NLWeb</u></a> is an open project developed by Microsoft that defines a standard protocol for natural-language queries on websites. Each NLWeb instance also operates as a Model Context Protocol (MCP) server. Cloudflare is building to this spec and actively working with Microsoft to extend the standard with the goal to let every site function like an AI app, so users and agents alike can query its contents naturally.</p><p><a href="https://developers.cloudflare.com/autorag/"><u>AutoRAG</u></a>, Cloudflare’s managed retrieval engine, can automatically crawl your website, store the content in R2, and embed it into a managed vector database. AutoRAG keeps the index fresh with continuous re-crawling and re-indexing. Model inference and embedding can be served through Workers AI. Each AutoRAG is paired with an AI Gateway that can provide <a href="https://www.cloudflare.com/learning/performance/what-is-observability/">observability and insights</a> into your AI model usage. This gives you a <a href="https://www.cloudflare.com/learning/ai/how-to-build-rag-pipelines/">complete, managed pipeline</a> for conversational search without the burden of managing custom infrastructure.</p><blockquote><p><i>“Together, NLWeb and AutoRAG let publishers go beyond search boxes, making conversational interfaces for websites simple to create and deploy. This integration will enable every website to easily become AI-ready for both people and trusted agents.”</i> – R.V. Guha, creator of NLWeb, CVP and Technical Fellow at Microsoft. </p></blockquote><p>We are optimistic this will open up new monetization models for publishers:</p><blockquote><p><i>"The challenges publishers have faced are well known, as are the risks of AI accelerating the collapse of already challenged business models. However, with NLWeb and AutoRAG, there is an opportunity to reset the nature of relationships with audiences for the better. More direct engagement on Publisher Owned and Operated (O&amp;O) environments, where audiences value the brand and voice of the Publisher, means new potential for monetization. This would be the reset the entire industry needs."</i>  – Joe Marchese, General &amp; Build Partner at Human Ventures.</p></blockquote>
    <div>
      <h2>One-Click to Make Your Site Conversational</h2>
      <a href="#one-click-to-make-your-site-conversational">
        
      </a>
    </div>
    <p>By combining NLWeb's standard with Cloudflare’s AutoRAG infrastructure, we’re making it possible to  easily bring conversational search to any website.</p><p>Simply select your domain in AutoRAG, and it will crawl and index your site for semantic querying. It then deploys a Cloudflare Worker, which acts as the access layer. This Worker implements the NLWeb standard and UI defined by the <a href="https://github.com/nlweb-ai/NLWeb"><u>NLWeb project</u></a> and exposes your indexed content to both people and AI agents.

The Worker includes:</p><ul><li><p><b>`/ask` endpoint:</b> The defined standard for how conversational web searches should be served. Powers the conversational UI at the root `/` as well as the embeddable preview at `/snippet.html`. It supports chat history so queries can build on one another within the same session, and includes automatic query decontextualization to improve retrieval quality.</p></li><li><p><b>`/mcp` endpoint: </b>Implements an MCP server that trusted AI agents can connect to for structured access.</p></li></ul><p>With this setup, your site content is immediately available in two ways for you to experiment: through a conversational UI that you can serve to your visitors, and through a structured MCP interface that lets trusted agents query your site reliably on your terms.</p><p>Additionally, if you prefer to deploy and host your own version of the NLWeb project, there’s also the option to use AutoRAG as the retrieval engine powering the <a href="https://github.com/nlweb-ai/NLWeb/blob/main/docs/setup-cloudflare-autorag.md"><u>NLWeb instance</u></a>.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1SM7rSQDhoR4fH5KgAJPD7/2266dc2e3c80f3fcc7f17014eb1d0cf1/image5.png" />
          </figure>
    <div>
      <h2>How Your Site Becomes Conversational</h2>
      <a href="#how-your-site-becomes-conversational">
        
      </a>
    </div>
    
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/xkeREv3GwXwBZw52Dg6XQ/caeb587819d08eff53a33aa893032b78/image2.png" />
          </figure><p>From your perspective, making your site conversational is just a single click. Behind the scenes, AutoRAG spins up a full retrieval pipeline to make that possible:</p><ol><li><p><b>Crawling and ingestion: </b>AutoRAG explores your site like a search engine, following `sitemap.xml` and `robots.txt` files to understand what pages are available and allowed for crawling. From there, it follows your sitemap to discover pages within your domain (up to 100k pages). <a href="https://developers.cloudflare.com/browser-rendering/"><u>Browser Rendering</u></a> is used to load each page so that it can capture dynamic, JavaScript content. Crawled pages are downloaded into an <a href="https://developers.cloudflare.com/r2/"><u>R2 bucket</u></a> in your account before being ingested. </p></li><li><p><b>Continuous Indexing:</b> Once ingested, the content is parsed and embedded into <a href="https://developers.cloudflare.com/vectorize/"><u>Vectorize</u></a>, making it queryable beyond keyword matching through semantic search. AutoRAG automatically re-crawls and re-indexes to keep your knowledge base aligned with your latest content.</p></li><li><p><b>Access &amp; Observability: </b>A Cloudflare Worker is deployed in your account to serve as the access layer that implements the NLWeb protocol (you can also find the deployable Worker in the Workers <a href="https://github.com/cloudflare/templates"><u>templates repository</u></a>). Workers AI is used to seamlessly power the summarization and decontextualized query capabilities to improve responses. <i>Soon, with the</i><a href="http://blog.cloudflare.com/ai-gateway-aug-2025-refresh/"><i><u> AI Gateway and Secret Store BYO keys</u></i></a><i>, you’ll be able to connect models from any provider and select them directly in the AutoRAG dashboard.</i></p></li></ol>
    <div>
      <h2>Road to Making Websites a First-Class Data Source</h2>
      <a href="#road-to-making-websites-a-first-class-data-source">
        
      </a>
    </div>
    <p>Until now, <a href="https://developers.cloudflare.com/autorag/concepts/how-autorag-works/"><u>AutoRAG</u></a> only supported R2 as a data source. That worked well for structured files, but we needed to make a website itself a first-class data source to be indexed and searchable. Making that possible meant building website crawling into AutoRAG and strengthening the system to handle large, dynamic sources like websites.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5ouTCcbipVX3s1fPgg6hEs/541a03efb4365370fee5df67cd68841f/image4.png" />
          </figure><p>Before implementing our web crawler, we needed to improve the reliability of data syncs. Prior users of AutoRAG lacked visibility into when indexing syncs ran and whether they were successful. To fix this, we introduced a Job module to track all syncs, store history, and provide logs. This required two new Durable Objects to be added into AutoRAG’s architecture:</p><ul><li><p><b>JobManager</b> runs a complete sync, and its duties include queuing files, embedding content, and keeping the Vectorize database up to date.  To ensure data consistency, only one JobManager can run per RAG at a time, enforced by the RagManager (a Durable Object in our existing architecture), which cancels any running jobs before starting new ones which can be triggered either manually or by a scheduled sync.</p></li><li><p><b>FileManager</b> solved scalability issues we hit when Workers ran out of memory during parallel processing. Originally, a single Durable Object was responsible for handling multiple files, but with a 128MB memory limit it quickly became a bottleneck. The solution was to break the work apart: JobManager now distributes files across many FileManagers, each responsible for a single file. By processing 20 files in parallel through 20 different FileManagers, we expanded effective memory capacity from 128MB to roughly 2.5GB per batch.</p></li></ul><p>With these improvements, we were ready to build the website parser. By reusing our existing R2-based queuing logic, we added crawling with minimal disruption:</p><ol><li><p>A JobManager designated for a website crawl begins by reading the sitemaps associated with the RAG configuration.</p></li><li><p>Instead of listing objects from an R2 bucket, it queues each website link into our existing R2-based queue, using the full URL as the R2 object key.</p></li><li><p>From here, the process is nearly identical to our file-based sync. A FileManager picks up the job and checks if the RAG is configured for website parsing.</p></li><li><p>If it is, the FileManager crawls the link and places the page's HTML contents into the user's R2 bucket, again using the URL as the object key.</p></li></ol><p>After these steps, we index the data and serve it at query time. This approach maximized code reuse, and any improvements to our <a href="https://blog.cloudflare.com/markdown-for-agents/">HTML-to-Markdown conversion</a> now benefit both file and website-based RAGs automatically.</p>
    <div>
      <h2>Get Started Today</h2>
      <a href="#get-started-today">
        
      </a>
    </div>
    <p>Getting your website ready for conversational search through NLWeb and AutoRAG is simple. Here’s how:</p><ol><li><p>In the <b>Cloudflare Dashboard</b>, navigate to <b>Compute &amp; AI &gt; AutoRAG</b>.</p></li><li><p>Select <b>Create</b> in AutoRAG, then choose the <b>NLWeb Website</b> quick deploy option.</p></li><li><p>Select the <b>domain</b> from your Cloudflare account that you want indexed.</p></li><li><p>Click <b>Start indexing</b>.</p></li></ol><p>That’s it! You can now try out your NLWeb search experience via the provided link, and test out how it will look on your site by using the embeddable snippet.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/dI9xwOKdn3jGkYKWK8NEN/e25ae13199eb09577868e421cc1fef7d/image1.png" />
          </figure><p>We’d love to hear your feedback as you experiment with this new capability and share your thoughts with us at <a>nlweb@cloudflare.com</a>.</p><p></p> ]]></content:encoded>
            <category><![CDATA[AI Week]]></category>
            <category><![CDATA[AI]]></category>
            <category><![CDATA[Search Engine]]></category>
            <category><![CDATA[Microsoft]]></category>
            <category><![CDATA[Auto Rag]]></category>
            <guid isPermaLink="false">1FRpZMePLmgD9cPqJnMFKS</guid>
            <dc:creator>Catarina Pires Mota</dc:creator>
            <dc:creator>Gabriel Massadas</dc:creator>
            <dc:creator>Nelson Duarte</dc:creator>
            <dc:creator>Daniel Leal</dc:creator>
            <dc:creator>Anni Wang</dc:creator>
        </item>
        <item>
            <title><![CDATA[Robotcop: enforcing your robots.txt policies and stopping bots before they reach your website]]></title>
            <link>https://blog.cloudflare.com/ai-audit-enforcing-robots-txt/</link>
            <pubDate>Tue, 10 Dec 2024 14:00:00 GMT</pubDate>
            <description><![CDATA[ The AI Crawl Control (formerly AI Audit) now allows you to quickly see which AI services are honoring your robots.txt policies and then automatically enforce the policies against those that aren’t.
 ]]></description>
            <content:encoded><![CDATA[ <p>Cloudflare’s <a href="https://blog.cloudflare.com/cloudflare-ai-audit-control-ai-content-crawlers/"><u>AI Crawl Control </u><i><u>(formerly AI Audit)</u></i></a><i> </i>dashboard allows you to easily understand how AI companies and services access your content. AI Crawl Control gives a summary of request counts broken out by bot, detailed path summaries for more granular insights, and the ability to filter by categories like <b>AI Search</b> or <b>AI Crawler</b>.</p><p>Today, we're going one step further. You can now quickly see which AI services are honoring your robots.txt policies, which aren’t, and then programmatically enforce these policies. </p>
    <div>
      <h3>What is robots.txt?</h3>
      <a href="#what-is-robots-txt">
        
      </a>
    </div>
    <p><a href="https://www.cloudflare.com/learning/bots/what-is-robots-txt/"><u>Robots.txt</u></a> is a plain text file hosted on your domain that implements the <a href="https://www.rfc-editor.org/rfc/rfc9309.html"><u>Robots Exclusion Protocol</u></a>, a standard that has been around since 1994. This file tells crawlers like Google, Bing, and many others which parts of your site, if any, they are allowed to access. </p><p>There are many reasons why site owners would want to define which portions of their websites crawlers are allowed to access: they might not want certain content available on search engines or social networks, they might trust one platform more than another, or they might simply want to reduce automated traffic to their servers.</p><p>With the advent of <a href="https://www.cloudflare.com/learning/ai/what-is-generative-ai/"><u>generative AI</u></a>, AI services have started crawling the Internet to collect training data for their models. These models are often proprietary and commercial and are used to generate new content. Many content creators and publishers that want to exercise control over how their content is used have started using robots.txt to declare policies that cover these AI bots, in addition to the traditional search engines.</p><p>Here’s an abbreviated real-world example of the robots.txt policy from a top online news site:</p>
            <pre><code>User-agent: GPTBot
Disallow: /

User-agent: ChatGPT-User
Disallow: /

User-agent: anthropic-ai
Disallow: /

User-agent: Google-Extended
Disallow: /

User-agent: Bytespider
Disallow: /
</code></pre>
            <p>This policy declares that the news site doesn't want ChatGPT, Anthropic AI, Google Gemini, or ByteDance’s Bytespider to crawl any of their content.</p>
    <div>
      <h3>From voluntary compliance to enforcement</h3>
      <a href="#from-voluntary-compliance-to-enforcement">
        
      </a>
    </div>
    <p>Compliance with the Robots Exclusion Protocol has historically been voluntary. </p><p>That’s where our new feature comes in. We’ve extended <a href="https://blog.cloudflare.com/cloudflare-ai-audit-control-ai-content-crawlers/"><u>AI Crawl Control</u></a> to give our customers both the visibility into how AI services providers honor their robots.txt policies <i>and</i> the ability to enforce those policies at the network level in your <a href="https://developers.cloudflare.com/waf/"><u>WAF</u></a>. </p><p>Your robots.txt file declares your policy, but now we can help you enforce it. You might even call it … your Robotcop.  </p>
    <div>
      <h3>How it works</h3>
      <a href="#how-it-works">
        
      </a>
    </div>
    <p>AI Crawl Control takes the robots.txt files from your web properties, parses them, and then matches their rules against the AI bot traffic we see for the selected property. The summary table gives you an aggregated view of the number of requests and violations we see for every Bot across all paths. If you hover your mouse over the Robots.txt column, we will show you the defined policies for each Bot in the tooltip. You can also filter by violations from the top of the page. </p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/o2hHH0Nm68muUzaxmbx7E/0b9c2acfb33f2ca2d59e00625b4d0fc7/BLOG-2619_2.png" />
          </figure><p>In the “Most popular paths” section, whenever a path in your site gets traffic that has violated your policy, we flag it for visibility. Ideally, you wouldn't see violations in the Robots.txt column — if you do see them, someone's not complying.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1o5sChT2d6QK8JNPejImVk/79590e1721644a2fd067784bb9ce862e/BLOG-2619_3.png" />
          </figure><p>But that's not all… More importantly, AI Crawl Control allows you to enforce your robots.txt policy at the network level. By pressing the "Enforce robots.txt rules" button on the top of the summary table, we automatically translate the rules defined for AI Bots in your robots.txt into an advanced firewall rule, redirect you to the WAF configuration screen, and allow you to deploy the rule in our network.</p><p>This is how the robots.txt policy mentioned above looks after translation:</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5qYJG3RcvrDxzVDtb28Q2J/d73d7dcea94acb261e9fc525427c2e77/BLOG-2619_4.png" />
          </figure><p>Once you deploy a WAF rule built from your robots.txt policies, you are no longer simply requesting that AI services respect your policy, you're enforcing it.</p>
    <div>
      <h3>Conclusion</h3>
      <a href="#conclusion">
        
      </a>
    </div>
    <p>With AI Crawl Control, we are giving our customers even more visibility into how AI services access their content, helping them define their policies and then enforcing them at the network level.</p><p>This feature is live today for all Cloudflare customers. Simply log into the dashboard and navigate to your domain to begin auditing the bot traffic from AI services and enforcing your robots.txt directives.</p> ]]></content:encoded>
            <category><![CDATA[AI]]></category>
            <category><![CDATA[Network Services]]></category>
            <category><![CDATA[Application Services]]></category>
            <category><![CDATA[security.txt]]></category>
            <guid isPermaLink="false">6Bi6mGvw8vrskNZ7Mmp73F</guid>
            <dc:creator>Celso Martinho</dc:creator>
            <dc:creator>Will Allen</dc:creator>
            <dc:creator>Nelson Duarte</dc:creator>
        </item>
        <item>
            <title><![CDATA[Billions and billions (of logs): scaling AI Gateway with the Cloudflare Developer Platform]]></title>
            <link>https://blog.cloudflare.com/billions-and-billions-of-logs-scaling-ai-gateway-with-the-cloudflare/</link>
            <pubDate>Thu, 24 Oct 2024 13:00:00 GMT</pubDate>
            <description><![CDATA[ How we scaled AI Gateway to handle and store billions of requests, using Cloudflare Workers, D1, Durable Objects, and R2. ]]></description>
            <content:encoded><![CDATA[ <p>With the rapid advancements occurring in the AI space, developers face significant challenges in keeping up with the ever-changing landscape. New models and providers are continuously emerging, and understandably, developers want to experiment and test these options to find the best fit for their use cases. This creates the need for a streamlined approach to managing multiple models and providers, as well as a centralized platform to efficiently monitor usage, implement controls, and gather data for optimization.</p><p><a href="https://developers.cloudflare.com/ai-gateway/"><u>AI Gateway</u></a> is specifically designed to address these pain points. Since its launch in <a href="https://blog.cloudflare.com/announcing-ai-gateway"><u>September 2023</u></a>, AI Gateway has empowered developers and organizations by successfully proxying over 2 billion requests in just one year, as we <a href="https://blog.cloudflare.com/workers-ai-bigger-better-faster/#optimizing-ai-workflows-with-ai-gateway"><u>highlighted during September’s Birthday Week</u></a>. With AI Gateway, developers can easily store, analyze, and optimize their AI <a href="https://www.cloudflare.com/learning/ai/inference-vs-training/"><u>inference</u></a> requests and responses in real time.</p><p>With our initial architecture, AI Gateway faced a significant challenge: the logs, those critical trails of data interactions between applications and AI models, could only be retained for 30 minutes. This limitation was not just a minor inconvenience; it posed a substantial barrier for developers and businesses needing to analyze long-term patterns, ensure compliance, or simply debug over more extended periods.</p><p>In this post, we'll explore the technical challenges and strategic decisions behind extending our log storage capabilities from 30 minutes to being able to store billions of logs indefinitely. We'll discuss the challenges of scale, the intricacies of data management, and how we've engineered a system that not only meets the demands of today, but is also scalable for the future of AI development.</p>
    <div>
      <h2>Background</h2>
      <a href="#background">
        
      </a>
    </div>
    <p>AI Gateway is built on <a href="https://workers.cloudflare.com"><u>Cloudflare Workers</u></a>, a serverless platform that runs on the Cloudflare network, allowing developers to write small JavaScript functions that can execute at the point of need, near the user, on Cloudflare's vast network of data centers, without worrying about platform scalability.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6jV3iKCN771ixU21Hixfpz/18086a52cfe05cd20f1c94bbba21e293/_BLOG-2593_2.png" />
          </figure><p>Our customers use multiple providers and models and are always looking to optimize the way they do inference. And, of course, in order to evaluate their prompts, performance, cost, and to troubleshoot what’s going on, AI Gateway’s customers need to store requests and responses. New requests show up within 15 seconds and customers can check a request’s cost, duration, number of tokens, and provide their feedback (thumbs up or down).</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/RBqZXnLJNCaQPbtbzjQmj/70aa2598f9b9294b67db8cd5712a6345/_BLOG-2593_3.png" />
          </figure><p>This scales in a way where an account can have multiple gateways and each gateway has its own settings. In our first implementation, a backend worker was responsible for storing Real Time Logs and other background tasks. However, in the rapidly evolving domain of artificial intelligence, where real-time data is as precious as the insights it provides, <a href="https://www.cloudflare.com/learning/performance/log-retention-best-practices/">managing log data efficiently</a> becomes paramount. We recognized that to truly empower our users, we needed to offer a solution where logs weren't just transient records but could be stored permanently. Permanent log storage means developers can now track the performance, security, and operational insights of their AI applications over time, enabling not only immediate troubleshooting but also longitudinal studies of AI behavior, usage trends, and system health.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1TcC1ZdyNzT0xwFwme2oBt/a9202691a0a983fa3eafdf6c0ee92f2c/_BLOG-2593_4.png" />
          </figure><p>The diagram above describes our old architecture, which could only store 30 minutes of data.</p><p>Tracing the path of a request through the AI Gateway, as depicted in the sequence above:</p><ol><li><p>A developer sends a new inference request, which is first received by our Gateway Worker.</p></li><li><p>The Gateway Worker then performs several checks: it looks for cached results, enforces rate limits, and verifies any other configurations set by the user for their gateway. Provided all conditions are met, it forwards the request to the selected inference provider (in this diagram, OpenAI).</p></li><li><p>The inference provider processes the request and sends back the response.</p></li><li><p>Simultaneously, as the response is relayed back to the developer, the request and response details are also dispatched to our Backend Worker. This worker's role is to manage and store the log of this transaction.</p></li></ol>
    <div>
      <h2>The challenge: Store two billion logs</h2>
      <a href="#the-challenge-store-two-billion-logs">
        
      </a>
    </div>
    
    <div>
      <h3>First step: real-time logs</h3>
      <a href="#first-step-real-time-logs">
        
      </a>
    </div>
    <p>Initially, the AI Gateway project stored both request metadata and the actual request bodies in a <a href="https://developers.cloudflare.com/d1/"><u>D1 database</u></a>. This approach facilitated rapid development in the project's infancy. However, as customer engagement grew, the <a href="https://www.cloudflare.com/developer-platform/products/d1/">D1 database</a> began to fill at an accelerating rate, eventually retaining logs for only 30 minutes at a time.</p><p>To mitigate this, we first optimized the database schema, which extended the log retention to one hour. However, we soon encountered diminishing returns due to the sheer volume of byte data from the request bodies. Post-launch, it became clear that a more scalable solution was necessary. We decided to migrate the request bodies to R2 storage, significantly alleviating the data load on D1. This adjustment allowed us to incrementally extend log retention to 24 hours.</p><p>Consequently, D1 functioned primarily as a log index, enabling users to search and filter logs efficiently. When users needed to view details or download a log, these actions were seamlessly proxied through to R2.</p><p>This dual-system approach provided us with the breathing room to contemplate and develop more sophisticated storage solutions for the future.</p>
    <div>
      <h3>Second step: persistent logs and Durable Object transactional storage</h3>
      <a href="#second-step-persistent-logs-and-durable-object-transactional-storage">
        
      </a>
    </div>
    <p>As our traffic surged, we encountered a growing number of requests from customers wanting to access and compare older logs.</p><p>Upon learning that the Durable Objects team was seeking beta testers for their new <a href="https://blog.cloudflare.com/sqlite-in-durable-objects/"><u>Durable Objects with SQLite</u></a>, we eagerly signed up.</p><p>Originally, we considered Durable Objects as the ideal solution for expanding our log storage capacity, which required us to shard the logs by a unique string. Initially, this string was the account ID, but during a mid-development load test, we hit a cap at 10 million logs per Durable Object. This limitation meant that each account could only support up to this number of logs.</p><p>Given our commitment to the DO migration, we saw an opportunity rather than a constraint. To overcome the 10 million log limit per account, we refined our approach to shard by both account ID and gateway name. This adjustment effectively raised the storage ceiling from 10 million logs per account to 10 million per gateway. With the default setting allowing each account up to 10 gateways, the potential storage for each account skyrocketed to 100 million logs.</p><p>This strategic pivot not only enabled us to store a significantly larger number of logs. But also enhanced our flexibility in gateway management. Now, when a gateway is deleted, we can simply remove the corresponding Durable Object.</p><p>Additionally, this sharding method isolates high-volume request scenarios. If one customer's heavy usage slows down log insertion, it only impacts their specific Durable Object, thereby preserving performance for other customers.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3Q6degDA3V02dZFVugW2LO/ae121890a3d4493e5c01459c477f32d9/_BLOG-2593_5.png" />
          </figure><p>Taking a glance at the revised architecture diagram, we replaced the Backend Worker with our newly integrated Durable Object. The rest of the request flow remains unchanged, including the concurrent response to the user and the interaction with the Durable Object, which occurs in the fourth step.</p><p>Leveraging Cloudflare’s network, our Gateway Worker operates near the user's location, which in turn positions the user's Durable Object close by. This proximity significantly enhances the speed of log insertion and query operations.</p>
    <div>
      <h3>Third step: managing thousands of Durable Objects</h3>
      <a href="#third-step-managing-thousands-of-durable-objects">
        
      </a>
    </div>
    <p>As the number of users and requests on AI Gateway grows, managing each unique Durable Object (DO) becomes increasingly complex. New customers join continuously, and we needed an efficient method to track each DO, ensure users stay within their 10 gateway limit, and manage the storage capacity for free users.</p><p>To address these challenges, we introduced another layer of control with a new Durable Object we've named the Account Manager. The primary function of the Account Manager is straightforward yet crucial: it keeps user activities in check.</p><p>Here's how it works: before any Gateway commits a new log to permanent storage, it consults the Account Manager. This check determines whether the gateway is allowed to insert the log based on the user's current usage and entitlements. The Account Manager uses its own SQLite database to verify the total number of rows a user has and their service level. If all checks pass, it signals the Gateway that the log can be inserted. It was paramount to guarantee that this entire validation process occurred in the background, ensuring that the user experience remains seamless and uninterrupted.</p><p>The Account Manager stays updated by periodically receiving data from each Gateway’s Durable Object. Specifically, after every 1000 inference requests, the Gateway sends an update on its total rows to the Account Manager, which then updates its local records. This system ensures that the Account Manager has the most current data when making its decisions.</p><p>Additionally, the Account Manager is responsible for monitoring customer entitlements. It tracks whether an account is on a free or paid plan, how many gateways a user is permitted to create, and the log storage capacity allocated to each gateway. </p><p>Through these mechanisms, the Account Manager not only helps in maintaining system integrity but also ensures fair usage across all users of AI Gateway.</p>
    <div>
      <h2>AI evaluations and Durable Objects sharding</h2>
      <a href="#ai-evaluations-and-durable-objects-sharding">
        
      </a>
    </div>
    <p>As we continue to develop evaluations to fully automatic and, in the future, use Large Language Models (LLMs),  we are now taking the first step towards this goal and launching the open beta phase of comprehensive <a href="https://blog.cloudflare.com/workers-ai-bigger-better-faster/#optimizing-ai-workflows-with-ai-gateway"><u>AI evaluations</u></a>, centered on Human-in-the-Loop feedback.</p><p>This feature empowers users to create bespoke datasets from their application logs, thereby enabling them to score and evaluate the performance, speed, and cost-effectiveness of their models, with a primary focus on LLMs and automated scoring, analyzing the performance of LLMs, providing developers with objective, data-driven insights to refine their models.</p><p>To do this, developers require a reliable logging mechanism that persists logs from multiple gateways, storing up to 100 million logs in total (10 million logs per gateway, across 10 gateways). This represents a significant volume of data, as each request made through the AI Gateway generates a log entry, with some log entries potentially exceeding 50 MB in size.</p><p>This necessity leads us to work on the expansion of log storage capabilities. Since log storage is limited to 10 million logs per gateway, in future iterations, we aim to scale this capacity by implementing sharded Durable Objects (DO), allowing multiple Durable Objects per gateway to handle and store logs. This scaling strategy will enable us to store significantly larger volumes of logs, providing richer data for evaluations (using LLMs as a judge or from user input), all through AI Gateway.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7FLy2JEfvGFo8P7PCVBZYT/a4d6367341e9fc224dedaad3aa0f02e2/_BLOG-2593_6.png" />
          </figure>
    <div>
      <h2>Coming Soon</h2>
      <a href="#coming-soon">
        
      </a>
    </div>
    <p>We are working on improving our existing <a href="https://developers.cloudflare.com/ai-gateway/providers/universal/"><u>Universal Endpoint</u></a>, the next step on an enhanced solution that builds on existing fallback mechanisms to offer greater resilience, flexibility, and intelligence in request management.</p><p>Currently, when a provider encounters an error or is unavailable, our system <a href="https://developers.cloudflare.com/ai-gateway/configuration/fallbacks/"><u>falls back</u></a> to an alternative provider to ensure continuity. The improved Universal Endpoint takes this a step further by introducing automatic retry capabilities, allowing failed requests to be reattempted before fallback is triggered. This significantly improves reliability by handling transient errors and increasing the likelihood of successful request fulfillment. It will look something like this:</p>
            <pre><code>curl --location 'https://aig.example.com/' \
--header 'CF-AIG-TOKEN: Bearer XXXX' \
--header 'Content-Type: application/json' \
--data-raw '[
    {
        "id": "0001",
        "provider": "openai",
        "endpoint": "chat/completions",
        "headers": {
            "Authorization": "Bearer XXXX",
            "Content-Type": "application/json"
        },
        "query": {
            "model": "gpt-3.5-turbo",
            "messages": [
                {
                    "role": "user",
                    "content": "generate a prompt to create cloudflare random images"
                }
            ]
        },
        "option": {
            "retry": 2,
            "delay": 200,
            "onComplete": {
                "provider": "workers-ai",
                "endpoint": "@cf/stabilityai/stable-diffusion-xl-base-1.0",
                "headers": {
                    "Authorization": "Bearer XXXXXX",
                    "Content-Type": "application/json"
                },
                "query": {
                    "messages": [
                        {
                            "role": "user",
                            "content": "&lt;prompt-response id='\''0001'\'' /&gt;"
                        }
                    ]
                }
            }
        }
    },
    {
        "provider": "workers-ai",
        "endpoint": "@cf/stabilityai/stable-diffusion-xl-base-1.0",
        "headers": {
            "Authorization": "Bearer XXXXXX",
            "Content-Type": "application/json"
        },
        "query": {
            "messages": [
                {
                    "role": "user",
                    "content": "create a image of a missing cat"
                }
            ]
        }
    }
]'</code></pre>
            <p>The request to the improved Universal Endpoint system demonstrates how it handles multiple providers with integrated retry mechanisms and fallback logic. In this example, the first request is sent to a provider like OpenAI, asking it to generate a text-to-image prompt. The “retry” option ensures that transient issues don’t result in immediate failure.</p><p>The system’s ability to seamlessly switch between providers while applying retry strategies ensures higher reliability and robustness in managing requests. By leveraging fallback logic, the Improved Universal Endpoint can dynamically adapt to provider failures, ensuring that tasks are completed successfully even in complex, multi-step workflows.</p><p>In addition to retry logic, we will have the ability to inspect requests and responses and make dynamic decisions based on the content of the result. This enables developers to create conditional workflows where the system can adapt its behavior depending on the nature of the response, creating a highly flexible and intelligent decision-making process.</p><p>If you haven’t yet used AI Gateway, check out our <a href="https://developers.cloudflare.com/ai-gateway/"><u>developer documentation</u></a> on how to get started. If you have any questions, reach out on our <a href="http://discord.cloudflare.com/"><u>Discord channel</u></a>.</p> ]]></content:encoded>
            <category><![CDATA[AI]]></category>
            <category><![CDATA[AI Gateway]]></category>
            <category><![CDATA[Durable Objects]]></category>
            <category><![CDATA[D1]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <guid isPermaLink="false">2LUyKREpCJjJ5qGqwZyoAx</guid>
            <dc:creator>Catarina Pires Mota</dc:creator>
            <dc:creator>Gabriel Massadas</dc:creator>
            <dc:creator>Nelson Duarte</dc:creator>
        </item>
        <item>
            <title><![CDATA[Email Routing subdomain support, new APIs and security protocols]]></title>
            <link>https://blog.cloudflare.com/email-routing-subdomains/</link>
            <pubDate>Thu, 26 Oct 2023 13:10:06 GMT</pubDate>
            <description><![CDATA[ It's been two years since we announced Email Routing, our solution to create custom email addresses for your domains and route incoming emails to your preferred mailbox. Since then, the team has worked hard to evolve the product and add more powerful features to meet our users' expectations.  ]]></description>
            <content:encoded><![CDATA[ <p></p><p>It's been two years since we announced Email Routing, our solution to create custom email addresses for your domains and route incoming emails to your preferred mailbox. Since then, the team has worked hard to evolve the product and add more powerful features to meet our users' expectations. Examples include <a href="/announcing-route-to-workers/">Route to Workers</a>, which allows you to <a href="https://developers.cloudflare.com/email-routing/email-workers/">process your Emails programmatically</a> using Workers scripts, <a href="/email-routing-leaves-beta/">Public APIs</a>, Audit Logs, or <a href="/dmarc-management/">DMARC Management</a>.</p><p>We also made significant progress in supporting more email security extensions and protocols, protecting our customers from unwanted traffic, and keeping our IP space reputation for email egress impeccable to maximize our deliverability rates to whatever inbox upstream provider you chose.</p><p>Since <a href="/email-routing-leaves-beta/">leaving beta</a>, Email Routing has grown into one of our most popular products; it’s used by more than one million different customer zones globally, and we forward around 20 million messages daily to every major email platform out there. Our product is mature, robust enough for general usage, and suitable for any production environment. And it keeps evolving: today, we announce three new features that will help make Email Routing more secure, flexible, and powerful than ever.</p>
    <div>
      <h2>New security protocols</h2>
      <a href="#new-security-protocols">
        
      </a>
    </div>
    <p>The SMTP email protocol has been around since the early 80s. Naturally, it wasn't designed with the best security practices and requirements in mind, at least not the ones that the Internet expects today. For that reason, several protocol revisions and extensions have been standardized and adopted by the community over the years. Cloudflare is known for being an early adopter of promising emerging technologies; Email Routing already <a href="https://developers.cloudflare.com/email-routing/postmaster/">supports</a> things like SPF, DKIM signatures, DMARC policy enforcement, TLS transport, STARTTLS, and IPv6 egress, to name a few. Today, we are introducing support for two new standards to help <a href="https://www.cloudflare.com/zero-trust/products/email-security/">increase email security</a> and improve deliverability to third-party upstream email providers.</p>
    <div>
      <h3>ARC</h3>
      <a href="#arc">
        
      </a>
    </div>
    <p><a href="https://arc-spec.org/">Authenticated Received Chain</a> (ARC) is an email authentication system designed to allow an intermediate email server (such as Email Routing) to preserve email authentication results. In other words, with ARC, we can securely preserve the results of validating sender authentication mechanisms like SPF and DKIM, which we support when the email is received, and transport that information to the upstream provider when we forward the message. ARC establishes a chain of trust with all the hops the message has passed through. So, if it was tampered with or changed in one of the hops, it is possible to see where by following that chain.</p><p>We began rolling out ARC support to Email Routing a few weeks ago. Here’s how it works:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/67xk7IFzgYjOSwQEqUSbY/d48e08b735580f20fcafca988bb43748/pasted-image-0--1--2.png" />
            
            </figure><p>As you can see, <code>joe@example.com</code> sends an Email to <code>henry@domain.example</code>, an Email Routing address, which in turn is forwarded to the final address, <code>example@gmail.com</code>.</p><p>Email Routing will use <code>@example.com</code>’s DMARC policy to check the SPF and DKIM alignments (SPF, DKIM, and DMARC <a href="https://www.cloudflare.com/learning/email-security/dmarc-dkim-spf/">help authenticate</a> email senders by verifying that the emails came from the domain that they claim to be from.) It then stores this authentication result by adding a <code>Arc-Authentication-Results</code> header in the message:</p>
            <pre><code>ARC-Authentication-Results: i=1; mx.cloudflare.net; dkim=pass header.d=cloudflare.com header.s=example09082023 header.b=IRdayjbb; dmarc=pass header.from=example.com policy.dmarc=reject; spf=none (mx.cloudflare.net: no SPF records found for postmaster@example.com) smtp.helo=smtp.example.com; spf=pass (mx.cloudflare.net: domain of joe@example.com designates 2a00:1440:4824:20::32e as permitted sender) smtp.mailfrom=joe@example.com; arc=none smtp.remote-ip=2a00:1440:4824:20::32e</code></pre>
            <p>Then we take a snapshot of all the headers and the body of the original message, and we generate an <code>Arc-Message-Signature</code> header with a DKIM-like cryptographic signature (in fact ARC uses the same DKIM keys):</p>
            <pre><code>ARC-Message-Signature: i=1; a=rsa-sha256; s=2022; d=email.cloudflare.net; c=relaxed/relaxed; h=To:Date:Subject:From:reply-to:cc:resent-date:resent-from:resent-to :resent-cc:in-reply-to:references:list-id:list-help:list-unsubscribe :list-subscribe:list-post:list-owner:list-archive; t=1697709687; bh=sN/+...aNbf==;</code></pre>
            <p>Finally, before forwarding the message to <code>example@gmail.com</code>, Email Routing generates the <code>Arc-Seal</code> header, another DKIM-like signature, composed out of the <code>Arc-Authentication-Results</code> and <code>Arc-Message-Signature</code>, and cryptographically “seals” the message:</p>
            <pre><code>ARC-Seal: i=1; a=rsa-sha256; s=2022; d=email.cloudflare.net; cv=none; b=Lx35lY6..t4g==;</code></pre>
            <p>When Gmail receives the message from Email Routing, it not only normally authenticates the last hop domain.example domain (Email Routing uses <a href="https://developers.cloudflare.com/email-routing/postmaster/#sender-rewriting">SRS</a>), but it also checks the ARC seal header, which provides the authentication results of the original sender.</p><p>ARC increases the traceability of the message path through email intermediaries, allowing for more informed delivery decisions by those who receive emails as well as higher deliverability rates for those who transport them, like Email Routing. It has been adopted by all the major email providers like <a href="https://support.google.com/a/answer/175365?hl=en">Gmail</a> and Microsoft. You can read more about the ARC protocol in the <a href="https://datatracker.ietf.org/doc/html/rfc8617">RFC8617</a>.</p>
    <div>
      <h3>MTA-STS</h3>
      <a href="#mta-sts">
        
      </a>
    </div>
    <p>As we said earlier, SMTP is an old protocol. Initially Email communications were done in the clear, in plain-text and unencrypted. At some point in time in the late 90s, the email providers community standardized STARTTLS, also known as Opportunistic TLS. The <a href="https://datatracker.ietf.org/doc/html/rfc3207">STARTTLS extension</a> allowed a client in a SMTP session to upgrade to TLS encrypted communications.</p><p>While at the time this seemed like a step forward in the right direction, we later found out that because STARTTLS can start with an unencrypted plain-text connection, and that can be hijacked, the protocol is <a href="https://lwn.net/Articles/866481/">susceptible to man-in-the-middle attacks</a>.</p><p>A few years ago MTA Strict Transport Security (<a href="https://datatracker.ietf.org/doc/html/rfc8461">MTA-STS</a>) was introduced by email service providers including Microsoft, Google and Yahoo as a solution to protect against downgrade and man-in-the-middle attacks in SMTP sessions, as well as solving the lack of security-first communication standards in email.</p><p>Suppose that <code>example.com</code> uses Email Routing. Here’s how you can enable MTA-STS for it.</p><p>First, log in to the <a href="https://dash.cloudflare.com/">Cloudflare dashboard</a> and select your account and zone. Then go to <b>DNS</b> &gt; <b>Records</b> and create a new CNAME record with the name “<code>_mta-sts</code>” that points to Cloudflare’s record “<code>_mta-sts.mx.cloudflare.net</code>”. Make sure to disable the proxy mode.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4czTYhSi9X5kPU3TZ0m861/e7d8162ff6f40494ce6d11fbf5899dad/pasted-image-0-2.png" />
            
            </figure><p>Confirm that the record was created:</p>
            <pre><code>$ dig txt _mta-sts.example.com
_mta-sts.example.com.	300	IN	CNAME	_mta-sts.mx.cloudflare.net.
_mta-sts.mx.cloudflare.net. 300	IN	TXT	"v=STSv1; id=20230615T153000;"</code></pre>
            <p>This tells the other end client that is trying to connect to us that we support MTA-STS.</p><p>Next you need an HTTPS endpoint at <code>mta-sts.example.com</code> to serve your policy file. This file defines the mail servers in the domain that use MTA-STS. The reason why HTTPS is used here instead of DNS is because not everyone uses DNSSEC yet, so we want to avoid another MITM attack vector.</p><p>To do this you need to deploy a very simple Worker that allows Email clients to pull Cloudflare’s Email Routing <a href="https://mta-sts.mx.cloudflare.net/.well-known/mta-sts.txt">policy</a> file using the <a href="https://en.wikipedia.org/wiki/Well-known_URI">“well-known” URI</a> convention. Go to your <b>Account</b> &gt; <b>Workers &amp; Pages</b> and press <b>Create Application</b>. Pick the “MTA-STS” template from the list.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6BBFtG8hiHehJw74L2DbHX/d2afee1d61f266382082c08681e05e1a/pasted-image-0--2--2.png" />
            
            </figure><p>This Worker simply proxies <code>https://mta-sts.mx.cloudflare.net/.well-known/mta-sts.txt</code> to your own domain. After deploying it, go to the Worker configuration, then <b>Triggers</b> &gt; <b>Custom Domains</b> and <b>Add Custom Domain</b>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7MWHc7AuevDzxafJ0gfaFb/f659d8c0ae8c30f9a1457bc4b20f3535/customdomains.png" />
            
            </figure><p>You can then confirm that your policy file is working:</p>
            <pre><code>$ curl https://mta-sts.example.com/.well-known/mta-sts.txt
version: STSv1
mode: enforce
mx: *.mx.cloudflare.net
max_age: 86400</code></pre>
            <p>This says that we enforce MTA-STS. Capable email clients will only deliver email to this domain over a secure connection to the specified MX servers. If no secure connection can be established the email will not be delivered.</p><p>Email Routing also supports MTA-STS upstream, which greatly improves security when forwarding your Emails to service providers like <a href="https://support.google.com/a/answer/9261504?hl=en">Gmail</a> or <a href="https://learn.microsoft.com/en-us/purview/enhancing-mail-flow-with-mta-sts">Microsoft</a>, and others.</p><p>While enabling MTA-STS involves a few steps today, we plan to simplify things for you and automatically configure MTA-STS for your domains from the Email Routing dashboard as a future improvement.</p>
    <div>
      <h2>Sending emails and replies from Workers</h2>
      <a href="#sending-emails-and-replies-from-workers">
        
      </a>
    </div>
    <p>Last year we announced <a href="https://developers.cloudflare.com/email-routing/email-workers/">Email Workers</a>, allowing anyone using Email Routing to associate a Worker script to an Email address rule, and programmatically process their incoming emails in any way they want. <a href="https://developers.cloudflare.com/workers/">Workers</a> is our serverless compute platform, it provides hundreds of features and APIs, like <a href="https://developers.cloudflare.com/workers/databases/">databases</a> and <a href="https://developers.cloudflare.com/r2/api/workers/workers-api-reference/">storage</a>. Email Workers opened doors to a flood of use-cases and applications that weren’t possible before like implementing allow/block lists, advanced rules, notifications to messaging applications, honeypot aggregators and more.</p><p>Still, you could only act on the incoming email event. You could read and process the email message, you could even manipulate and create some headers, but you couldn’t rewrite the body of the message or create new emails from scratch.</p><p>Today we’re announcing two new powerful Email Workers APIs that will further enhance what you can do with Email Routing and Workers.</p>
    <div>
      <h3>Send emails from Workers</h3>
      <a href="#send-emails-from-workers">
        
      </a>
    </div>
    <p>Now you can send an email from any Worker, from scratch, whenever you want, not just when you receive incoming messages, to any email address verified on Email Routing under your account. Here are a few practical examples where sending email from Workers to your verified addresses can be helpful:</p><ul><li><p>Daily digests with the news from your favorite publications.</p></li><li><p>Alert messages whenever the weather conditions are adverse.</p></li><li><p>Automatic notifications when systems complete tasks.</p></li><li><p>Receive a message composed of the inputs of a form online on a contact page.</p></li></ul><p>Let's see a simple example of a Worker sending an email. First you need to create “<code>send_email</code>” bindings in your wrangler.toml configuration:</p>
            <pre><code>send_email = [
    {type = "send_email", name = "EMAIL_OUT"}
 ]</code></pre>
            <p>And then creating a new message and sending it in a Workers is as simple as:</p>
            <pre><code>import { EmailMessage } from "cloudflare:email";
import { createMimeMessage } from "mimetext";

export default {
 async fetch(request, env) {
   const msg = createMimeMessage();
   msg.setSender({ name: "Workers AI story", addr: "joe@example.com" });
   msg.setRecipient("mary@domain.example");
   msg.setSubject("An email generated in a worker");
   msg.addMessage({
       contentType: 'text/plain',
       data: `Congratulations, you just sent an email from a worker.`
   });

   var message = new EmailMessage(
     "joe@example.com",
     "mary@domain.example",
     msg.asRaw()
   );
   try {
     await env.EMAIL_OUT.send(message);
   } catch (e) {
     return new Response(e.message);
   }

   return new Response("email sent!");
 },
};</code></pre>
            <p>This example makes use of <a href="https://muratgozel.github.io/MIMEText/">mimetext</a>, an open-source raw email message generator.</p><p>Again, for security reasons, you can only send emails to the addresses for which you confirmed ownership in Email Routing under your Cloudflare account. If you’re looking for sending email campaigns or newsletters to destination addresses that you do not control or larger subscription groups, you should consider other options like our <a href="/sending-email-from-workers-with-mailchannels/">MailChannels integration</a>.</p><p>Since sending Emails from Workers is not tied to the EmailEvent, you can send them from any type of Worker, including <a href="https://developers.cloudflare.com/workers/configuration/cron-triggers/">Cron Triggers</a> and <a href="https://developers.cloudflare.com/durable-objects/">Durable Objects</a>, whenever you want, you control all the logic.</p>
    <div>
      <h3>Reply to emails</h3>
      <a href="#reply-to-emails">
        
      </a>
    </div>
    <p>One of our most-requested features has been to provide a way to programmatically respond to incoming emails. It has been possible to do this with Email Workers in a very limited capacity by returning a permanent SMTP error message — but this may or may not be visible to the end user depending on the client implementation.</p>
            <pre><code>export default {
  async email(message, env, ctx) {
      message.setReject("Address not allowed");
  }
}
</code></pre>
            <p>As of today, you can now truly reply to incoming emails with another new message and implement smart auto-responders programmatically, adding any content and context in the main body of the message. Think of a customer support email automatically generating a ticket and returning the link to the sender, an out-of-office reply with instructions when you're on vacation, or a detailed explanation of why you rejected an email. Here’s a code example:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4NgbXFwy3Xw0VHLemZ4smZ/682a581c21af850880fada5bbc17e99f/Screenshot-2023-10-26-at-12.05.33.png" />
            
            </figure><p>To mitigate security risks and abuse, replying to incoming emails has a few requirements:</p><ul><li><p>The incoming email has to have valid DMARC.</p></li><li><p>The email can only be replied to once.</p></li><li><p>The <code>In-Reply-To</code> header of the reply message must match the <code>Message-ID</code> of the incoming message.</p></li><li><p>The recipient of the reply must match the incoming sender.</p></li><li><p>The outgoing sender domain must match the same domain that received the email.</p></li></ul><p>If these and other internal conditions are not met, then <code>reply()</code> will fail with an exception, otherwise you can freely compose your reply message and send it back to the original sender.</p><p>For more information the documentation to these APIs is available in our <a href="https://developers.cloudflare.com/email-routing/email-workers/runtime-api/">Developer Docs</a>.</p>
    <div>
      <h2>Subdomains support</h2>
      <a href="#subdomains-support">
        
      </a>
    </div>
    <p>This is a big one.</p><p>Email Routing is a <a href="https://developers.cloudflare.com/fundamentals/concepts/accounts-and-zones/#zones">zone-level</a> feature. A zone has a <a href="https://www.cloudflare.com/learning/dns/top-level-domain/">top-level domain</a> (the same as the zone name) and it can have subdomains (managed under the DNS feature.) As an example, I can have the <code>example.com</code>  zone, and then the <code>mail.example.com</code> and <code>corp.example.com</code> subdomains under it. However, we can only use Email Routing with the top-level domain of the zone, <code>example.com</code> in this example. While this is fine for the vast majority of use cases, some customers — particularly bigger organizations with complex email requirements — have asked for more flexibility.</p><p>This changes today. Now you can use Email Routing with any subdomain of any zone in your account. To make this possible we redesigned the dashboard UI experience to make it easier to get you started and manage all your Email Routing domains and subdomains, rules and destination addresses in one single place. Let’s see how it works.</p><p>To add Email Routing features to a new subdomain, log in to the <a href="https://dash.cloudflare.com/">Cloudflare dashboard</a> and select your account and zone. Then go to <b>Email</b> &gt; <b>Email Routing</b> &gt; <b>Settings</b> and click “Add subdomain”.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1WwS0LP1o8Ijlk0IzcqzCE/8528ed0f90a34029777d66b411d9e696/prev-req-rec.png" />
            
            </figure><p>Once the subdomain is added and the DNS records are configured, you can see it in the <b>Settings</b> list under the <b>Subdomains</b> section:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7gwBTgYQ36QxcvCGHfBqEd/450707647df2a8277eb0dc66e966088e/Domain.png" />
            
            </figure><p>Now you can go to <b>Email</b> &gt; <b>Email Routing</b> &gt; <b>Routing rules</b> and create new custom addresses that will show you the option of using either the top domain of the zone or any other configured subdomain.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1KJ9AIM6MpcaYeV5IrVZQw/1e306de0bd46177eb2601e8e4e600930/Screenshot-2023-10-25-at-11.55.31-AM.png" />
            
            </figure><p>After the new custom address for the subdomain is created you can see it in the list with all the other addresses, and manage it from there.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6vEJFroWoVivSr9n6SwPVl/28a4938f201e4153c964895d4687f1b2/custom-addresses.png" />
            
            </figure><p>It’s this easy.</p>
    <div>
      <h2>Final words</h2>
      <a href="#final-words">
        
      </a>
    </div>
    <p>We hope you enjoy the new features that we are announcing today. Still, we want to be clear: there are no changes in pricing, and Email Routing is still free for Cloudflare customers.</p><p>Ever since Email Routing was launched, we’ve been listening to customers’ feedback and trying to adjust our roadmap to both our requirements and their own ideas and requests. Email shouldn't be difficult; our goal is to listen, learn and keep improving the <a href="https://www.cloudflare.com/zero-trust/solutions/email-security-services/">email security service</a> with better, more powerful features.</p><p>You can find detailed information about the new features and more in our Email Routing <a href="https://developers.cloudflare.com/email-routing">Developer Docs</a>.</p><p>If you have any questions or feedback about Email Routing, please come see us in the <a href="https://community.cloudflare.com/new-topic?category=Feedback/Previews%20%26%20Betas&amp;tags=email">Cloudflare Community</a> and the <a href="https://discord.gg/cloudflaredev">Cloudflare Discord</a>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1OKqc3VieWKGRFBDtPU7io/18e8d2db548d341b0cb78a111aaa8480/Email-Routing-spot.png" />
            
            </figure><p></p> ]]></content:encoded>
            <category><![CDATA[Email Routing]]></category>
            <category><![CDATA[Email Workers]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <category><![CDATA[Developers]]></category>
            <guid isPermaLink="false">54W5SKQEt6kELFJMaWSRyh</guid>
            <dc:creator>Celso Martinho</dc:creator>
            <dc:creator>André Cruz</dc:creator>
            <dc:creator>Nelson Duarte</dc:creator>
        </item>
        <item>
            <title><![CDATA[How we built DMARC Management using Cloudflare Workers]]></title>
            <link>https://blog.cloudflare.com/how-we-built-dmarc-management/</link>
            <pubDate>Fri, 17 Mar 2023 13:00:00 GMT</pubDate>
            <description><![CDATA[ At Cloudflare, we use the Workers platform and our product stack to build new services. Read how we made the new DMARC Management solution entirely on top of our APIs.
 ]]></description>
            <content:encoded><![CDATA[ <p></p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3P7EqcZydcPUKVhQNdVwkr/55e20a63d7ae1ce2ff638c2818d7da58/How-we-built-DMARC-Management.png" />
            
            </figure>
    <div>
      <h3>What are DMARC reports</h3>
      <a href="#what-are-dmarc-reports">
        
      </a>
    </div>
    <p><a href="https://www.cloudflare.com/en-gb/learning/dns/dns-records/dns-dmarc-record/">DMARC</a> stands for Domain-based Message Authentication, Reporting, and Conformance. It's an email authentication protocol that helps protect against email <a href="https://www.cloudflare.com/learning/access-management/phishing-attack/">phishing</a> and <a href="https://www.cloudflare.com/learning/email-security/what-is-email-spoofing/">spoofing</a>.</p><p>When an email is sent, DMARC allows the domain owner to set up a DNS record that specifies which authentication methods, such as <a href="https://www.cloudflare.com/learning/dns/dns-records/dns-spf-record/">SPF</a> (Sender Policy Framework) and <a href="https://www.cloudflare.com/learning/dns/dns-records/dns-dkim-record/">DKIM</a> (DomainKeys Identified Mail), are used to verify the email's authenticity. When the email fails these authentication checks DMARC instructs the recipient's email provider on how to handle the message, either by quarantining it or rejecting it outright.</p><p>DMARC has become increasingly important in today's Internet, where email phishing and spoofing attacks are becoming more sophisticated and prevalent. By implementing DMARC, domain owners can protect their brand and their customers from the negative impacts of these attacks, including loss of trust, reputation damage, and financial loss.</p><p>In addition to <a href="https://www.cloudflare.com/learning/dns/dns-records/protect-domains-without-email/">protecting</a> against phishing and spoofing attacks, DMARC also provides <a href="https://www.rfc-editor.org/rfc/rfc7489">reporting</a> capabilities. Domain owners can receive reports on email authentication activity, including which messages passed and failed DMARC checks, as well as where these messages originated from.</p><p>DMARC management involves the configuration and maintenance of DMARC policies for a domain. Effective DMARC management requires ongoing monitoring and analysis of email authentication activity, as well as the ability to make adjustments and updates to DMARC policies as needed.</p><p>Some key components of effective DMARC management include:</p><ul><li><p>Setting up DMARC policies: This involves configuring the domain's DMARC record to specify the appropriate authentication methods and policies for handling messages that fail authentication checks. Here’s what a DMARC DNS record looks like:</p></li></ul><p><code>v=DMARC1; p=reject; rua=mailto:dmarc@example.com</code></p><p>This specifies that we are going to use DMARC version 1, our policy is to reject emails if they fail the DMARC checks, and the email address to which providers should send DMARC reports.</p><ul><li><p>Monitoring email authentication activity: DMARC reports are an important tool for domain owners to ensure <a href="https://www.cloudflare.com/zero-trust/products/email-security/">email security</a> and deliverability, as well as compliance with industry standards and regulations. By regularly monitoring and analyzing DMARC reports, domain owners can <a href="https://www.cloudflare.com/learning/email-security/how-to-prevent-phishing/">identify email threats</a>, optimize email campaigns, and improve overall email authentication.</p></li><li><p>Making adjustments as needed: Based on analysis of DMARC reports, domain owners may need to make adjustments to DMARC policies or authentication methods to ensure that email messages are properly authenticated and protected from phishing and spoofing attacks.</p></li><li><p>Working with email providers and third-party vendors: Effective DMARC management may require collaboration with email providers and third-party vendors to ensure that DMARC policies are being properly implemented and enforced.</p></li></ul><p>Today we launched <a href="/dmarc-management">DMARC management</a>. This is how we built it.</p>
    <div>
      <h3>How we built it</h3>
      <a href="#how-we-built-it">
        
      </a>
    </div>
    <p>As a leading provider of cloud-based security and performance solutions, we at Cloudflare take a specific approach to test our products. We "dogfood" our own tools and services, which means we use them to run our business. This helps us identify any issues or bugs before they affect our customers.</p><p>We use our own products internally, such as <a href="https://workers.cloudflare.com/">Cloudflare Workers</a>, a serverless platform that allows developers to run their code on our global network. Since its launch in 2017, the Workers ecosystem has grown significantly. Today, there are thousands of developers building and deploying applications on the platform. The power of the Workers ecosystem lies in its ability to enable developers to build sophisticated applications that were previously impossible or impractical to run so close to clients. Workers can be used to build APIs, generate dynamic content, optimize images, perform real-time processing, and much more. The possibilities are virtually endless. We used Workers to power services like <a href="/technology-behind-radar2/">Radar 2.0</a>, or software packages like <a href="/welcome-to-wildebeest-the-fediverse-on-cloudflare/">Wildebeest</a>.</p><p>Recently our <a href="https://developers.cloudflare.com/email-routing/">Email Routing</a> product joined forces with Workers, enabling <a href="/announcing-route-to-workers/">processing incoming emails</a> via Workers scripts. As the <a href="https://developers.cloudflare.com/email-routing/email-workers/">documentation</a> states: “With Email Workers you can leverage the power of Cloudflare Workers to implement any logic you need to <a href="https://www.cloudflare.com/learning/email-security/what-is-email-routing/">process your emails</a> and create complex rules. These rules determine what happens when you receive an email.” Rules and verified addresses can all be configured via our <a href="https://developers.cloudflare.com/api/operations/email-routing-destination-addresses-list-destination-addresses">API</a>.</p><p>Here’s how a simple Email Worker looks like:</p>
            <pre><code>export default {
  async email(message, env, ctx) {
    const allowList = ["friend@example.com", "coworker@example.com"];
    if (allowList.indexOf(message.headers.get("from")) == -1) {
      message.setReject("Address not allowed");
    } else {
      await message.forward("inbox@corp");
    }
  }
}</code></pre>
            <p>Pretty straightforward, right?</p><p>With the ability to programmatically process incoming emails in place, it seemed like the perfect way to handle incoming DMARC report emails in a scalable and efficient manner, letting Email Routing and Workers do the heavy lifting of receiving an unbound number of emails from across the globe. A high level description of what we needed is:</p><ol><li><p>Receive email and extract report</p></li><li><p>Publish relevant details to analytics platform</p></li><li><p>Store the raw report</p></li></ol><p>Email Workers enable us to do #1 easily. We just need to create a worker with an email() handler. This handler will receive the <a href="https://www.rfc-editor.org/rfc/rfc5321">SMTP</a> envelope elements, a pre-parsed version of the email headers, and a stream to read the entire raw email.</p><p>For #2 we can also look into the Workers platform, and we will find the <a href="https://developers.cloudflare.com/analytics/analytics-engine/">Workers Analytics Engine</a>. We just need to define an appropriate schema, which depends both on what’s present in the reports and the queries we plan to do later. Afterwards we can query the data using either the <a href="https://developers.cloudflare.com/analytics/graphql-api/">GraphQL</a> or <a href="https://developers.cloudflare.com/analytics/analytics-engine/sql-api/">SQL</a> API.</p><p>For #3 we don’t need to look further than our <a href="https://www.cloudflare.com/developer-platform/products/r2/">R2 object storage</a>. It is <a href="https://developers.cloudflare.com/r2/examples/demo-worker/">trivial</a> to access R2 from a Worker. After extracting the reports from the email we will store them in R2 for posterity.</p><p>We built this as a managed service that you can enable on your zone, and added a dashboard interface for convenience, but in reality all the tools are available for you to deploy your own DMARC reports processor on top of Cloudflare Workers, in your own account, without having to worry about servers, scalability or performance.</p>
    <div>
      <h3>Architecture</h3>
      <a href="#architecture">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3d55aU3WlGrgQcuc1TKPAF/a02a34f819174b82e768b0aed5053708/Screenshot-2023-03-16-at-4.18.08-PM.png" />
            
            </figure><p><a href="https://developers.cloudflare.com/email-routing/email-workers/">Email Workers</a> is a feature of our Email Routing product. The Email Routing component runs in all our nodes, so any one of them is able to process incoming mail, which is important because we announce the Email ingress BGP prefix from all our datacenters. Sending emails to an Email Worker is as easy as setting a rule in the Email Routing dashboard.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4tgjcPuXeJ3lJ9yLxQoPxz/7c9f34dd7ae03aeb2293e64df9ebf8e6/pasted-image-0--4--3.png" />
            
            </figure><p>When the Email Routing component receives an email that matches a rule to be delivered to a Worker, it will contact our internal version of the recently open-sourced <a href="https://github.com/cloudflare/workerd">workerd</a> runtime, which also runs on all nodes. The RPC schema that governs this interaction is defined in a <a href="https://github.com/capnproto/capnproto">Capnproto</a> schema, and allows the body of the email to be streamed to Edgeworker as it’s read. If the worker script decides to forward this email, Edgeworker will contact Email Routing using a capability sent in the original request.</p>
            <pre><code>jsg::Promise&lt;void&gt; ForwardableEmailMessage::forward(kj::String rcptTo, jsg::Optional&lt;jsg::Ref&lt;Headers&gt;&gt; maybeHeaders) {
  auto req = emailFwdr-&gt;forwardEmailRequest();
  req.setRcptTo(rcptTo);

  auto sendP = req.send().then(
      [](capnp::Response&lt;rpc::EmailMetadata::EmailFwdr::ForwardEmailResults&gt; res) mutable {
    auto result = res.getResponse().getResult();
    JSG_REQUIRE(result.isOk(), Error, result.getError());
  });
  auto&amp; context = IoContext::current();
  return context.awaitIo(kj::mv(sendP));
}
</code></pre>
            <p>In the context of DMARC reports this is how we handle the incoming emails:</p><ol><li><p>Fetch the recipient of the email being processed, this is the RUA that was used. RUA is a DMARC configuration parameter that indicates where aggregate DMARC processing feedback should be reported pertaining to a certain domain. This recipient can be found in the “to” attribute of the message.</p></li></ol>
            <pre><code>const ruaID = message.to</code></pre>
            <ol><li><p>Since we handle DMARC reports for an unbounded number of domains, we use Workers KV to store some information about each one and key this information on the RUA. This also lets us know if we should be receiving these reports.</p></li></ol>
            <pre><code>const accountInfoRaw = await env.KV_DMARC_REPORTS.get(dmarc:${ruaID})</code></pre>
            <ol><li><p>At this point, we want to read the entire email into an arrayBuffer in order to parse it. Depending on the size of the report we may run into the limits of the free Workers plan. If this happens, we recommend that you switch to the <a href="https://www.cloudflare.com/workers-unbound-beta/">Workers Unbound</a> resource model which does not have this issue.</p></li></ol>
            <pre><code>const rawEmail = new Response(message.raw)
const arrayBuffer = await rawEmail.arrayBuffer()</code></pre>
            <ol><li><p>Parsing the raw email involves, among other things, parsing its MIME parts. There are multiple libraries available that allow one to do this. For example, you could use <a href="https://www.npmjs.com/package/postal-mime">postal-mime</a>:</p></li></ol>
            <pre><code>const parser = new PostalMime.default()
const email = await parser.parse(arrayBuffer)</code></pre>
            <ol><li><p>Having parsed the email we now have access to its attachments. These attachments are the DMARC reports themselves and they can be compressed. The first thing we want to do is store them in their compressed form in <a href="https://developers.cloudflare.com/r2/data-access/workers-api/workers-api-usage/">R2</a> for long-term storage. They can be useful later on for re-processing or investigating interesting reports. Doing this is as simple as calling put() on the R2 binding. In order to facilitate retrieval later we recommend that you spread the report files across directories based on the current time.</p></li></ol>
            <pre><code>await env.R2_DMARC_REPORTS.put(
    `${date.getUTCFullYear()}/${date.getUTCMonth() + 1}/${attachment.filename}`,
    attachment.content
  )</code></pre>
            <ol><li><p>We now need to look into the attachment mime type. The raw form of DMARC reports is XML, but they can be compressed. In this case we need to decompress them first. DMARC reporter files can use multiple compression algorithms. We use the MIME type to know which one to use. For <a href="https://en.wikipedia.org/wiki/Zlib">Zlib</a> compressed reports <a href="https://www.npmjs.com/package/pako">pako</a> can be used while for ZIP compressed reports <a href="https://www.npmjs.com/package/unzipit">unzipit</a> is a good choice.</p></li><li><p>Having obtained the raw XML form of the report, <a href="https://www.npmjs.com/package/fast-xml-parser">fast-xml-parser</a> has worked well for us in parsing them. Here’s how the DMARC report XML looks:</p></li></ol>
            <pre><code>&lt;feedback&gt;
  &lt;report_metadata&gt;
    &lt;org_name&gt;example.com&lt;/org_name&gt;
    &lt;emaildmarc-reports@example.com&lt;/email&gt;
   &lt;extra_contact_info&gt;http://example.com/dmarc/support&lt;/extra_contact_info&gt;
    &lt;report_id&gt;9391651994964116463&lt;/report_id&gt;
    &lt;date_range&gt;
      &lt;begin&gt;1335521200&lt;/begin&gt;
      &lt;end&gt;1335652599&lt;/end&gt;
    &lt;/date_range&gt;
  &lt;/report_metadata&gt;
  &lt;policy_published&gt;
    &lt;domain&gt;business.example&lt;/domain&gt;
    &lt;adkim&gt;r&lt;/adkim&gt;
    &lt;aspf&gt;r&lt;/aspf&gt;
    &lt;p&gt;none&lt;/p&gt;
    &lt;sp&gt;none&lt;/sp&gt;
    &lt;pct&gt;100&lt;/pct&gt;
  &lt;/policy_published&gt;
  &lt;record&gt;
    &lt;row&gt;
      &lt;source_ip&gt;192.0.2.1&lt;/source_ip&gt;
      &lt;count&gt;2&lt;/count&gt;
      &lt;policy_evaluated&gt;
        &lt;disposition&gt;none&lt;/disposition&gt;
        &lt;dkim&gt;fail&lt;/dkim&gt;
        &lt;spf&gt;pass&lt;/spf&gt;
      &lt;/policy_evaluated&gt;
    &lt;/row&gt;
    &lt;identifiers&gt;
      &lt;header_from&gt;business.example&lt;/header_from&gt;
    &lt;/identifiers&gt;
    &lt;auth_results&gt;
      &lt;dkim&gt;
        &lt;domain&gt;business.example&lt;/domain&gt;
        &lt;result&gt;fail&lt;/result&gt;
        &lt;human_result&gt;&lt;/human_result&gt;
      &lt;/dkim&gt;
      &lt;spf&gt;
        &lt;domain&gt;business.example&lt;/domain&gt;
        &lt;result&gt;pass&lt;/result&gt;
      &lt;/spf&gt;
    &lt;/auth_results&gt;
  &lt;/record&gt;
&lt;/feedback&gt;</code></pre>
            <ol><li><p>We now have all the data in the report at our fingertips. What we do from here on depends a lot on how we want to present the data. For us, the goal was to display meaningful data extracted from them in our Dashboard. Therefore we needed an Analytics platform where we could push the enriched data. Enter, <a href="https://developers.cloudflare.com/analytics/analytics-engine/">Workers Analytics Engine</a>. The Analytics engine is perfect for this task since it allows us to <a href="https://developers.cloudflare.com/analytics/analytics-engine/get-started/#3-write-data-from-your-worker">send</a> data to it from a worker, and exposes a <a href="https://developers.cloudflare.com/analytics/graphql-api/">GraphQL API</a> to interact with the data afterwards. This is how we obtain the data to show in our dashboard.</p></li></ol><p>In the future, we are also considering integrating <a href="https://developers.cloudflare.com/queues/">Queues</a> in the workflow to asynchronously process the report and avoid waiting for the client to complete it.</p><p>We managed to implement this project end-to-end relying only on the Workers infrastructure, proving that it’s possible, and advantageous, to build non-trivial apps without having to worry about scalability, performance, storage and security issues.</p>
    <div>
      <h3>Open sourcing</h3>
      <a href="#open-sourcing">
        
      </a>
    </div>
    <p>As we mentioned before, we built a managed service that you can enable and use, and we will manage it for you. But, everything we did can also be deployed by you, in your account, so that you can manage your own DMARC reports. It’s easy, and free. To help you with that, we are releasing an open-source version of a Worker that processes DMARC reports in the way described above: <a href="https://github.com/cloudflare/dmarc-email-worker">https://github.com/cloudflare/dmarc-email-worker</a></p><p>If you don’t have a dashboard where to show the data, you can also <a href="https://developers.cloudflare.com/analytics/analytics-engine/worker-querying/">query</a> the Analytics Engine from a Worker. Or, if you want to store them in a relational database, then there’s <a href="https://developers.cloudflare.com/d1/platform/client-api/">D1</a> to the rescue. The possibilities are endless and we are excited to find out what you’ll build with these tools.</p><p>Please contribute, make your own, we’ll be listening.</p>
    <div>
      <h3>Final words</h3>
      <a href="#final-words">
        
      </a>
    </div>
    <p>We hope that this post has furthered your understanding of the Workers platform. Today Cloudflare takes advantage of this platform to build most of our services, and we think you should too.</p><p>Feel free to contribute to our open-source version and show us what you can do with it.</p><p>The Email Routing is also working on expanding the Email Workers API more functionally, but that deserves another blog soon.</p> ]]></content:encoded>
            <category><![CDATA[Security Week]]></category>
            <category><![CDATA[Email Security]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[DMARC]]></category>
            <guid isPermaLink="false">HNhMxPSjzPXyTdtRLp51K</guid>
            <dc:creator>André Cruz</dc:creator>
            <dc:creator>Nelson Duarte</dc:creator>
        </item>
        <item>
            <title><![CDATA[Email Routing leaves Beta]]></title>
            <link>https://blog.cloudflare.com/email-routing-leaves-beta/</link>
            <pubDate>Tue, 25 Oct 2022 13:00:00 GMT</pubDate>
            <description><![CDATA[ Today Email Routing leaves Beta and an update on all the new things we've been adding to the service, including behind-the-scenes and not-so-visible improvements ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Email Routing was <a href="/introducing-email-routing/">announced</a> during Birthday Week in 2021 and has been available for free to every Cloudflare customer since early this year. When we launched in beta, we set out to make a difference and provide the most <a href="/migrating-to-cloudflare-email-routing/">uncomplicated</a>, more powerful <a href="https://www.cloudflare.com/learning/email-security/what-is-email-routing/">email forwarding service</a> on the Internet for all our customers, for free.</p><p>We feel we've met and <a href="https://w3techs.com/technologies/details/em-cloudflare">surpassed</a> our goals for the first year. Cloudflare Email Routing is now one of our most popular features and a top leading email provider. We are processing email traffic for more than 550,000 inboxes and forwarding an average of two million messages daily, and still growing month to month.</p><p>In February, we also announced that we were <a href="/why-we-are-acquiring-area-1/">acquiring</a> Area1. Merging their team, products, and know-how with Cloudflare was a significant step in strengthening our <a href="https://www.cloudflare.com/zero-trust/products/email-security/">Email Security</a> capabilities.</p><p>All this is good, but what about more features, you ask?</p><p>The team has been working hard to enhance Email Routing over the last few months. <b>Today Email Routing leaves beta.</b></p><p>Also, we feel that this could be a good time to give you an update on all the new things we've been adding to the service, including behind-the-scenes and not-so-visible improvements.</p><p>Let’s get started.</p>
    <div>
      <h3>Public API and Terraform</h3>
      <a href="#public-api-and-terraform">
        
      </a>
    </div>
    <p>Cloudflare has a strong API-first philosophy. All of our services expose their primitives in our vast API catalog and gateway, which we then “dogfood” extensively. For instance, our customer's configuration dashboard is built entirely on top of these APIs.</p><p>The Email Routing APIs didn't quite make it to this catalog on day one and were kept private and undocumented for a while. This summer we made those APIs <a href="https://api.cloudflare.com/#email-routing-destination-addresses-properties">available</a> on the public Cloudflare API catalog. You can programmatically use them to manage your destination emails, rules, and other Email Routing settings. The methods' definitions and parameters are documented, and we provide <a href="https://curl.se/">curl</a> examples if you want to get your hands dirty quickly.</p><p>Even better, if you're an infrastructure as code type of user and use Terraform to configure your systems automatically, we have you covered too. The latest releases of <a href="https://registry.terraform.io/providers/cloudflare/cloudflare/">Cloudflare's Terraform provider</a> now <a href="https://github.com/cloudflare/terraform-provider-cloudflare/tree/master/internal/provider">incorporate</a> the Email Routing API resources, which you can use with <a href="https://www.terraform.io/language/syntax/configuration">HCL</a>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/oPdbQSpCrGdInWwSmc3Gz/bfa929155775e78998b86f6149b6ed9d/image4-11.png" />
            
            </figure>
    <div>
      <h3>IPv6 egress</h3>
      <a href="#ipv6-egress">
        
      </a>
    </div>
    <p>IPv6 adoption is on a <a href="https://radar.cloudflare.com/reports/ipv6">sustained growth</a> path. Our latest IPv6 adoption report shows that we're nearing the 30% penetration figure globally, with some countries, where mobile usage is prevalent, exceeding the 50% mark. Cloudflare has offered full IPv6 support <a href="/introducing-cloudflares-automatic-ipv6-gatewa/">since 2011</a> as it aligns entirely with our mission to help build a better Internet.</p><p>We are IPv6-ready across the board in our network and our products, and Email Routing has had IPv6 ingress support since day one.</p>
            <pre><code>➜  ~ dig celso.io MX +noall +answer
celso.io.		300	IN	MX	91 isaac.mx.cloudflare.net.
celso.io.		300	IN	MX	2 linda.mx.cloudflare.net.
celso.io.		300	IN	MX	2 amir.mx.cloudflare.net.
➜  ~ dig linda.mx.cloudflare.net AAAA +noall +answer
linda.mx.cloudflare.net. 300	IN	AAAA	2606:4700:f5::b
linda.mx.cloudflare.net. 300	IN	AAAA	2606:4700:f5::c
linda.mx.cloudflare.net. 300	IN	AAAA	2606:4700:f5::d</code></pre>
            <p>More recently, we closed the loop and added egress IPv6 as well. Now we also use IPv6 when sending emails to upstream servers. If the MX server to which an email is being forwarded supports IPv6, then we will try to use it. <a href="https://en.wikipedia.org/wiki/Comparison_of_webmail_providers">Gmail</a> is one good example of a high traffic destination that has IPv6 MX records.</p>
            <pre><code>➜  ~ dig gmail.com MX +noall +answer
gmail.com.		3362	IN	MX	30 alt3.gmail-smtp-in.l.google.com.
gmail.com.		3362	IN	MX	5 gmail-smtp-in.l.google.com.
gmail.com.		3362	IN	MX	10 alt1.gmail-smtp-in.l.google.com.
gmail.com.		3362	IN	MX	20 alt2.gmail-smtp-in.l.google.com.
gmail.com.		3362	IN	MX	40 alt4.gmail-smtp-in.l.google.com.
➜  ~ dig gmail-smtp-in.l.google.com AAAA +noall +answer
gmail-smtp-in.l.google.com. 116	IN	AAAA	2a00:1450:400c:c03::1a</code></pre>
            <p>We’re happy to report that we’re now delivering most of our email to upstreams using IPv6.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/fpqLS2x7AzUJBHUfBd1Vw/65e0089ca141515c51b2ff2df5a4716e/image1-22.png" />
            
            </figure>
    <div>
      <h3>Observability</h3>
      <a href="#observability">
        
      </a>
    </div>
    <p>Email Routing is effectively another system that sits in the middle of the life of an email message. No one likes to navigate blindly, especially when using and depending on critical services like email, so it's our responsibility to provide as much observability as possible about what's going on when messages are transiting through our network.</p><p>End to end email deliverability is a complex topic and often challenging to troubleshoot due to the nature of the protocol and the number of systems and hops involved. We added two widgets, Analytics and Detailed Logs, which will hopefully provide the needed <a href="/email-routing-insights/">insights</a> and help increase visibility.</p><p>The Analytics section of Email Routing shows general statistics about the number of emails received during the selected timeframe, how they got handled to the upstream destination addresses, and a convenient time-series chart.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5idsdXSP16hDLOxayDOGqi/6b62d3ce039cdd9d94abc0e69405594f/image5-4.png" />
            
            </figure><p>On the Activity Log, you can get detailed information about what happened to each individual message that was received and then delivered to the destination. That information includes the sender and the custom address used, the timestamp, and the delivery attempt result. It also has the details of our SPF, DMARC, and DKIM validations. We also provide filters to help you find what you're looking for in case your message volume is higher.</p><p>More recently, the Activity Log now also shows <a href="https://en.wikipedia.org/wiki/Bounce_message">bounces</a>. A bounce message happens when the upstream SMTP server accepts the delivery, but then, for any reason (exceeded quota, virus checks, forged messages, or other issues), the recipient inbox decides to reject it and return a new message back with an error to the latest <a href="https://en.wikipedia.org/wiki/Message_transfer_agent">MTA</a> in the chain, read from the <a href="https://www.rfc-editor.org/rfc/rfc5322.html#section-3.6.7">Return-Path</a> headers, which is us.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7wyT0gd7l6GHjl7LVFjCUR/67628c835e2f8f76f0d6a16ef99011be/image8-4.png" />
            
            </figure>
    <div>
      <h3>Audit Logs</h3>
      <a href="#audit-logs">
        
      </a>
    </div>
    <p><a href="https://developers.cloudflare.com/fundamentals/account-and-billing/account-security/review-audit-logs/">Audit Logs</a> are available on all plan types and summarize the history of events, like login and logout actions, or zone configuration changes, made within your Cloudflare account. Accounts with multiple members or companies that must comply with regulatory obligations rely on Audit logs for tracking and evidence reasons.</p><p>Email Routing now integrates with Audit Logs and records all configuration changes, like adding a new address, changing a rule, or editing the catch-all address. You can find the Audit Logs on the dashboard under "Manage Account" or use our API to download the list.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/15USXKo9itSQkX8h8JS0kE/ea244f54b31e72c73be3416ee42ace4e/image6-7.png" />
            
            </figure>
    <div>
      <h3>Anti-spam</h3>
      <a href="#anti-spam">
        
      </a>
    </div>
    <p>Unsolicited and malicious messages plague the world of email and are a big problem for end users. They affect the user experience and efficiency of email, and often carry security risks that can lead to scams, identity theft, and manipulation.</p><p>Since day one, we have supported and validated <a href="https://www.cloudflare.com/learning/dns/dns-records/dns-spf-record/">SPF</a> (Sender Policy Framework) records,  <a href="https://www.cloudflare.com/learning/dns/dns-records/dns-dkim-record/">DKIM</a> (DomainKeys Identified Mail) signatures, and <a href="https://www.cloudflare.com/learning/dns/dns-records/dns-dmarc-record/">DMARC</a> (Domain-based Message Authentication) policies in incoming messages. These steps are important and mitigate some risks associated with authenticating the origin of an email from a specific legitimate domain, but they don't solve the problem completely. You can still have bad actors generating spam or <a href="https://www.cloudflare.com/learning/email-security/how-to-identify-a-phishing-email/">phishing</a> Attacks from other domains who ignore SPF or DKIM completely.</p><p>Anti-spam techniques today are often based on blocking emails whose origin (the IP address of the client trying to deliver the message) confidence score isn't great. This is commonly known in the industry as IP reputation. Other companies specialize in maintaining reputation lists for IPs and email domains, also known as <a href="https://en.wikipedia.org/wiki/Domain_Name_System-based_blocklist">RBL</a> lists, which are then shared across providers and used widely.</p><p>Simply put, an IP or a domain gets a bad reputation when it starts sending unsolicited or malicious emails. If your IP or domain has a bad reputation, you'll have a hard time delivering Emails from them to any major email provider. A bad reputation goes away when the IP or domain stops acting bad.</p><p>Cloudflare is a security company that knows a few things about IP <a href="https://developers.cloudflare.com/ruleset-engine/rules-language/fields/#field-cf-threat_score">threat scores</a> and reputation. Working with the Area1 team and learning from them, we added support to flag and block emails received from what we consider bad IPs at the SMTP level. Our approach uses a combination of heuristics and reputation databases, including some RBL lists, which we constantly update.</p><p>This measure benefits not only those customers that receive a lot of spam, who will now get another layer of <a href="https://www.cloudflare.com/learning/dns/dns-records/protect-domains-without-email/">protection</a> and filtering, but also everyone else using Email Routing. The reputation of our own IP space and forwarding domain, which we use to deliver messages to other email providers, will improve, and with it, so will our deliverability success rate.</p>
    <div>
      <h3>IDN support</h3>
      <a href="#idn-support">
        
      </a>
    </div>
    <p><a href="https://datatracker.ietf.org/doc/html/rfc5891">Internationalized domain names</a>, or IDNs for short, are domains that contain at least one non-ASCII character. To accommodate backward compatibility with older Internet protocols and applications, the IETF approved the IDNA protocol (Internationalized Domain Names in Applications), which was then adopted by <a href="https://chromium.googlesource.com/chromium/src/+/main/docs/idn.md">many browsers</a>, <a href="https://www.cloudflare.com/learning/dns/glossary/what-is-a-domain-name-registrar/">top-level domain registrars</a> and other service providers.</p><p>Cloudflare was <a href="/non-latinutf8-domains-now-fully-supported/">one of the first</a> platforms to adopt IDNs back in 2012.  Supporting internationalized domain names on email, though, is challenging. Email uses DNS, SMTP, and other standards (like TLS and DKIM signatures) stacked on top of each other. IDNA conversions need to work end to end, or something will break.</p><p>Email Routing didn’t support IDNs until now. Starting today, Email Routing can be used with IDNs and everything will work end to end as expected.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2w5ochqMtILwVjTYbA0Pb/659ce2e551b0ea0e8540045dd48839e7/image3-10.png" />
            
            </figure>
    <div>
      <h3>8-bit MIME transport</h3>
      <a href="#8-bit-mime-transport">
        
      </a>
    </div>
    <p>The SMTP protocol supports extensions since the <a href="https://www.rfc-editor.org/rfc/rfc2821">RFC 2821</a> revision. When an email client connects to an SMTP server, it announces its capabilities on the EHLO command.</p>
            <pre><code>➜  ~ telnet linda.mx.cloudflare.net 25
Trying 162.159.205.24...
Connected to linda.mx.cloudflare.net.
Escape character is '^]'.
220 mx.cloudflare.net Cloudflare Email ESMTP Service ready
EHLO celso.io
250-mx.cloudflare.net greets celso.io
250-STARTTLS
250-8BITMIME
250 ENHANCEDSTATUSCODES</code></pre>
            <p>This tells our client that we support the <a href="https://www.ietf.org/rfc/rfc3207.txt">Secure SMTP</a> over TLS, <a href="https://www.rfc-editor.org/rfc/rfc2034.html">Enhanced Error Codes</a>, and the <a href="https://www.rfc-editor.org/rfc/rfc6152">8-bit MIME Transport</a>, our latest addition.</p><p>Most modern clients and servers support the 8BITMIME extension, making transmitting binary files easier and more efficient without additional conversions to and from 7-bit.</p><p>Email Routing now supports transmitting 8BITMIME SMTP messages end to end and handles DKIM signatures accordingly.</p>
    <div>
      <h3>Other fixes</h3>
      <a href="#other-fixes">
        
      </a>
    </div>
    <p>We’ve been making other smaller improvements to Email Routing too:</p><ul><li><p>We ported our SMTP server to use <a href="https://boringssl.googlesource.com/boringssl/">BoringSSL</a>, Cloudflare’s SSL/TLS <a href="/make-ssl-boring-again/">implementation of choice</a>, and now support more ciphers when clients connect to us using STARTTLS and when we connect to upstream servers.</p></li><li><p>We made a number of improvements when we added our own <a href="https://datatracker.ietf.org/doc/html/rfc6376">DKIM signatures</a> in the messages. We keep our <a href="https://www.rust-lang.org/">Rust</a> ?DKIM <a href="https://github.com/cloudflare/dkim">implementation</a> open source on GitHub, and we also <a href="https://github.com/lettre/lettre/commits/master">contribute</a> to <a href="https://github.com/lettre/lettre">Lettre</a>, a Rust mailer library that we use.</p></li><li><p>When a destination address domain has multiple MX records, we now try them all in their preference value order, as described in the <a href="https://datatracker.ietf.org/doc/html/rfc974">RFC</a>, until we get a good delivery, or we fail.</p></li></ul>
    <div>
      <h3>Route to Workers update</h3>
      <a href="#route-to-workers-update">
        
      </a>
    </div>
    <p>We announced <a href="/announcing-route-to-workers/">Route to Workers</a> in May this year. Route to Workers enables everyone to programmatically process their emails and use them as triggers for any other action. In other words, you can choose to process any incoming email with a Cloudflare Worker script and then implement any logic you wish before you deliver it to a destination address or drop it. Think about it as programmable email.</p><p>The good news, though, is that we're near completing the project. The APIs, the dashboard configuration screens, the SMTP service, and the necessary <a href="https://github.com/cloudflare/workerd/blob/main/src/workerd/io/worker-interface.capnp">Cap'n Proto interface</a> to Workers are mostly complete, and "all" we have left now is adding the Email Workers primitives to the runtime and testing the hell out of everything before we ship.</p><p>Thousands of users are waiting for Email Workers to start creating advanced email processing workflows, and we're excited about the possibilities this will open. We promise we're working hard to open the public beta as soon as possible.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/xNqMMpydzI8i8kWisriPT/d01bb6f42e9fe4bad92e8fec3796f6b4/image7-4.png" />
            
            </figure>
    <div>
      <h3>What’s next?</h3>
      <a href="#whats-next">
        
      </a>
    </div>
    <p>We keep looking at ways to improve email and will add more features and support to emerging protocols and extensions. Two examples are <a href="https://en.wikipedia.org/wiki/Authenticated_Received_Chain">ARC</a> (Authenticated Received Chain), a new signature-based authentication system designed with email forwarding services in mind, and <a href="https://datatracker.ietf.org/doc/html/rfc4952">EAI</a> (Email Address Internationalization), which we will be supporting soon.</p><p>In the meantime, you can start using Email Routing with your own domain if you haven't yet, it only <a href="/migrating-to-cloudflare-email-routing/">takes a few minutes</a> to set up, and it's free. Our <a href="https://developers.cloudflare.com/email-routing/">Developers Documentation page</a> has details on how to get started, troubleshooting, and technical information.</p><p>Ping us on our <a href="https://discord.com/invite/cloudflaredev">Discord server</a>, <a href="https://community.cloudflare.com/new-topic?category=Feedback/Previews%20%26%20Betas&amp;tags=email">community forum</a>, or <a href="https://twitter.com/cloudflare">Twitter</a> if you have suggestions or questions, the team is listening.</p> ]]></content:encoded>
            <category><![CDATA[Email]]></category>
            <category><![CDATA[Email Routing]]></category>
            <category><![CDATA[Email Workers]]></category>
            <guid isPermaLink="false">eSf4sLZdb5Gb9Y7mVbjOl</guid>
            <dc:creator>Celso Martinho</dc:creator>
            <dc:creator>André Cruz</dc:creator>
            <dc:creator>Nelson Duarte</dc:creator>
        </item>
    </channel>
</rss>