<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Qasim Muhammad</title>
    <description>The latest articles on Forem by Qasim Muhammad (@qasim157).</description>
    <link>https://forem.com/qasim157</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3837851%2F1a2b79c0-c959-45ef-b215-a68515f17bef.jpg</url>
      <title>Forem: Qasim Muhammad</title>
      <link>https://forem.com/qasim157</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/qasim157"/>
    <language>en</language>
    <item>
      <title>Manage Nylas Applications, Connectors, and Grants from the CLI</title>
      <dc:creator>Qasim Muhammad</dc:creator>
      <pubDate>Mon, 11 May 2026 02:09:02 +0000</pubDate>
      <link>https://forem.com/qasim157/manage-nylas-applications-connectors-and-grants-from-the-cli-3f30</link>
      <guid>https://forem.com/qasim157/manage-nylas-applications-connectors-and-grants-from-the-cli-3f30</guid>
      <description>&lt;p&gt;The &lt;code&gt;nylas admin&lt;/code&gt; commands let you manage your Nylas infrastructure without the web dashboard. Create applications, configure provider connectors, manage OAuth credentials, and monitor grants — all from the terminal.&lt;/p&gt;

&lt;h2&gt;
  
  
  What nylas admin does
&lt;/h2&gt;

&lt;p&gt;Full API management surface: applications, callback URIs, provider connectors (Google, Microsoft, IMAP), credentials, and grants. Useful for CI/CD pipelines, multi-tenant setups, and infrastructure-as-code workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Start
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;nylas/nylas-cli/nylas
nylas init
nylas admin applications list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Key commands
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas admin applications list&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List all applications&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas admin applications create&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create a new application&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas admin connectors list&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List provider connectors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas admin connectors create&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create a Google/Microsoft/IMAP connector&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas admin credentials list &amp;lt;connector-id&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List credentials for a connector&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas admin credentials create&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add OAuth credentials&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas admin callback-uris list&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List OAuth callback URIs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas admin callback-uris create --url &amp;lt;url&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Register a new callback URI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas admin grants list&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List all grants on the application&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas admin grants stats&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show grant statistics&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Creating an application and connector
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create app&lt;/span&gt;
nylas admin applications create &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"prod-email"&lt;/span&gt; &lt;span class="nt"&gt;--json&lt;/span&gt;

&lt;span class="c"&gt;# Add Google connector&lt;/span&gt;
nylas admin connectors create &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--provider&lt;/span&gt; google &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--client-id&lt;/span&gt; &lt;span class="nv"&gt;$GOOGLE_CLIENT_ID&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--client-secret&lt;/span&gt; &lt;span class="nv"&gt;$GOOGLE_CLIENT_SECRET&lt;/span&gt;

&lt;span class="c"&gt;# Register callback URI&lt;/span&gt;
nylas admin callback-uris create &lt;span class="nt"&gt;--url&lt;/span&gt; https://myapp.com/oauth/callback
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Monitoring grants
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# How many users are connected?&lt;/span&gt;
nylas admin grants stats &lt;span class="nt"&gt;--json&lt;/span&gt;

&lt;span class="c"&gt;# List all grants with their status&lt;/span&gt;
nylas admin grants list &lt;span class="nt"&gt;--json&lt;/span&gt; | jq &lt;span class="s1"&gt;'.[] | {id, provider, status}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Related posts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/qasim157/from-gmail-oauth-hell-to-one-line-agent-identity-cpp"&gt;From Gmail OAuth hell to one-line agent identity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/qasim157/track-every-action-your-ai-agent-takes-audit-logs-auth-management-compliance-for-cli-automation-33de"&gt;Track Every Action Your AI Agent Takes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;All commands:&lt;/strong&gt; &lt;a href="https://cli.nylas.com/docs/commands" rel="noopener noreferrer"&gt;Nylas CLI Command Reference&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Get started:&lt;/strong&gt; &lt;code&gt;brew install nylas/nylas-cli/nylas&lt;/code&gt; — &lt;a href="https://cli.nylas.com/guides/getting-started" rel="noopener noreferrer"&gt;other install methods&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cli</category>
      <category>devops</category>
      <category>api</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Agent Policies and Rules — Control What Your AI Agent Can Send and Receive</title>
      <dc:creator>Qasim Muhammad</dc:creator>
      <pubDate>Mon, 11 May 2026 02:08:56 +0000</pubDate>
      <link>https://forem.com/qasim157/agent-policies-and-rules-control-what-your-ai-agent-can-send-and-receive-1aen</link>
      <guid>https://forem.com/qasim157/agent-policies-and-rules-control-what-your-ai-agent-can-send-and-receive-1aen</guid>
      <description>&lt;p&gt;The &lt;code&gt;nylas agent policy&lt;/code&gt; and &lt;code&gt;nylas agent rule&lt;/code&gt; commands define guardrails for AI agent email accounts. Set who the agent can email, what triggers are allowed, and what actions to take on inbound messages — all enforced server-side.&lt;/p&gt;

&lt;h2&gt;
  
  
  What policies and rules do
&lt;/h2&gt;

&lt;p&gt;A policy is a named container for rules. Rules define conditions and actions: "if the sender is external, block" or "if sending to a non-internal domain, require approval." These fire before the agent sees the message, so prompt injection can't bypass them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Start
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nylas agent policy create &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"production-guardrails"&lt;/span&gt; &lt;span class="nt"&gt;--json&lt;/span&gt;
nylas agent rule create &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"internal-only-outbound"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--condition&lt;/span&gt; &lt;span class="s2"&gt;"recipient_domain != company.com"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--action&lt;/span&gt; block
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Key commands
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas agent policy list&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List all policies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas agent policy create --name N&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create a named policy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas agent policy get &amp;lt;id&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show policy details&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas agent policy delete &amp;lt;id&amp;gt; --yes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Delete a policy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas agent rule list&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List all rules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas agent rule create --name N --condition C --action A&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create a rule from flags&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas agent rule create --data-file rule.json&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create from JSON file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas agent rule get &amp;lt;id&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show a rule&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas agent rule delete &amp;lt;id&amp;gt; --yes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Delete a rule&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas agent account create &amp;lt;email&amp;gt; --policy-id &amp;lt;id&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Attach policy to agent&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Example: restrict outbound to internal domains only
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create policy&lt;/span&gt;
&lt;span class="nv"&gt;POLICY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;nylas agent policy create &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"internal-only"&lt;/span&gt; &lt;span class="nt"&gt;--json&lt;/span&gt; | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.id'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Add rule: block any outbound to non-company domains&lt;/span&gt;
nylas agent rule create &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--policy-id&lt;/span&gt; &lt;span class="nv"&gt;$POLICY&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"block-external-send"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--condition&lt;/span&gt; &lt;span class="s2"&gt;"direction == outbound AND recipient_domain != mycompany.com"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--action&lt;/span&gt; block

&lt;span class="c"&gt;# Attach to agent account&lt;/span&gt;
nylas agent account create agent@mycompany.nylas.email &lt;span class="nt"&gt;--policy-id&lt;/span&gt; &lt;span class="nv"&gt;$POLICY&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Example: auto-archive marketing emails
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nylas agent rule create &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"archive-marketing"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--condition&lt;/span&gt; &lt;span class="s2"&gt;"sender_domain IN (marketing.example.com, promo.example.com)"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--action&lt;/span&gt; archive
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Related posts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/qasim157/i-gave-my-claude-code-agent-an-email-address-14hc"&gt;I gave my Claude Code agent an email address&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/qasim157/ai-agents-need-email-your-mcp-setup-is-incomplete-without-it-ic6"&gt;AI agents need email — your MCP setup is incomplete&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/qasim157/5-nylas-cli-commands-every-ai-agent-should-have-access-to-2e87"&gt;5 Nylas CLI commands every AI agent should have&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;All commands:&lt;/strong&gt; &lt;a href="https://cli.nylas.com/docs/commands" rel="noopener noreferrer"&gt;Nylas CLI Command Reference&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Get started:&lt;/strong&gt; &lt;code&gt;brew install nylas/nylas-cli/nylas&lt;/code&gt; — &lt;a href="https://cli.nylas.com/guides/getting-started" rel="noopener noreferrer"&gt;other install methods&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cli</category>
      <category>aiagents</category>
      <category>security</category>
      <category>email</category>
    </item>
    <item>
      <title>Manage Email Signatures from the CLI — Create, List, and Attach to Sends</title>
      <dc:creator>Qasim Muhammad</dc:creator>
      <pubDate>Mon, 11 May 2026 02:08:52 +0000</pubDate>
      <link>https://forem.com/qasim157/manage-email-signatures-from-the-cli-create-list-and-attach-to-sends-2154</link>
      <guid>https://forem.com/qasim157/manage-email-signatures-from-the-cli-create-list-and-attach-to-sends-2154</guid>
      <description>&lt;p&gt;The &lt;code&gt;nylas email signatures&lt;/code&gt; commands manage reusable email signatures stored per-grant. Create HTML signatures once, attach them to any send with a flag — no more pasting footers manually.&lt;/p&gt;

&lt;h2&gt;
  
  
  What email signatures do
&lt;/h2&gt;

&lt;p&gt;Signatures are HTML blocks stored server-side and attached to outgoing emails via &lt;code&gt;--signature-id&lt;/code&gt;. Create different signatures for different contexts (formal, casual, department) and switch between them per-send.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Start
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nylas email signatures create &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"Work"&lt;/span&gt; &lt;span class="nt"&gt;--body&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;p&amp;gt;— Qasim&amp;lt;br&amp;gt;Staff SRE, Nylas&amp;lt;/p&amp;gt;"&lt;/span&gt;
nylas email send &lt;span class="nt"&gt;--to&lt;/span&gt; alice@example.com &lt;span class="nt"&gt;--subject&lt;/span&gt; &lt;span class="s2"&gt;"Hello"&lt;/span&gt; &lt;span class="nt"&gt;--body&lt;/span&gt; &lt;span class="s2"&gt;"..."&lt;/span&gt; &lt;span class="nt"&gt;--signature-id&lt;/span&gt; SIG_ID
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Key commands
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas email signatures list&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List stored signatures&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas email signatures show &amp;lt;id&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show signature HTML&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas email signatures create --name N --body B&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create from inline HTML&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas email signatures create --name N --body-file FILE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create from HTML file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas email signatures update &amp;lt;id&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Update a signature&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas email signatures delete &amp;lt;id&amp;gt; --yes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Delete a signature&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Creating a signature from a file
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; sig.html &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
&amp;lt;p style="font-family: sans-serif; font-size: 14px;"&amp;gt;
  &amp;lt;strong&amp;gt;Qasim Muhammad&amp;lt;/strong&amp;gt;&amp;lt;br&amp;gt;
  Staff SRE · Nylas&amp;lt;br&amp;gt;
  &amp;lt;a href="https://cli.nylas.com"&amp;gt;cli.nylas.com&amp;lt;/a&amp;gt;
&amp;lt;/p&amp;gt;
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;nylas email signatures create &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"Default"&lt;/span&gt; &lt;span class="nt"&gt;--body-file&lt;/span&gt; sig.html &lt;span class="nt"&gt;--json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using a signature when sending
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nylas email send &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--to&lt;/span&gt; team@company.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--subject&lt;/span&gt; &lt;span class="s2"&gt;"Weekly update"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--body&lt;/span&gt; &lt;span class="s2"&gt;"Here's the summary..."&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--signature-id&lt;/span&gt; &amp;lt;sig-id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The signature HTML is appended to the email body automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related posts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/qasim157/send-email-from-any-linux-server-in-60-seconds-no-smtp-config-11ac"&gt;Send email from any Linux server in 60 seconds&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/qasim157/automate-your-entire-email-workflow-from-the-terminal-no-smtp-no-sendmail-5apo"&gt;Automate Your Entire Email Workflow from the Terminal&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;All commands:&lt;/strong&gt; &lt;a href="https://cli.nylas.com/docs/commands" rel="noopener noreferrer"&gt;Nylas CLI Command Reference&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Get started:&lt;/strong&gt; &lt;code&gt;brew install nylas/nylas-cli/nylas&lt;/code&gt; — &lt;a href="https://cli.nylas.com/guides/getting-started" rel="noopener noreferrer"&gt;other install methods&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cli</category>
      <category>email</category>
      <category>productivity</category>
      <category>devtools</category>
    </item>
    <item>
      <title>Hosted Email Templates — Create, Render, and Send with Variable Substitution</title>
      <dc:creator>Qasim Muhammad</dc:creator>
      <pubDate>Mon, 11 May 2026 02:08:47 +0000</pubDate>
      <link>https://forem.com/qasim157/hosted-email-templates-create-render-and-send-with-variable-substitution-10af</link>
      <guid>https://forem.com/qasim157/hosted-email-templates-create-render-and-send-with-variable-substitution-10af</guid>
      <description>&lt;p&gt;The &lt;code&gt;nylas template&lt;/code&gt; commands manage hosted email templates with variable substitution. Define a template once, render it with dynamic data, and send — no local files needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  What hosted templates do
&lt;/h2&gt;

&lt;p&gt;Templates are stored in Nylas and rendered server-side. Use &lt;code&gt;{{variable}}&lt;/code&gt; placeholders for dynamic content (names, dates, URLs). Templates support HTML and plain text, with Mustache-style variable interpolation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Start
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nylas template create &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"welcome"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--subject&lt;/span&gt; &lt;span class="s2"&gt;"Welcome, {{name}}!"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--body&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;h1&amp;gt;Hey {{name}}&amp;lt;/h1&amp;gt;&amp;lt;p&amp;gt;Your account is ready.&amp;lt;/p&amp;gt;"&lt;/span&gt;

nylas email send &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--to&lt;/span&gt; new-user@example.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--template-id&lt;/span&gt; TPL_ID &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--template-data&lt;/span&gt; &lt;span class="s1"&gt;'{"name": "Alice"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Key commands
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas template list&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List hosted templates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas template create --name N --subject S --body B&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create a template&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas template show &amp;lt;id&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show template details&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas template update &amp;lt;id&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Update a template&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas template delete &amp;lt;id&amp;gt; --yes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Delete a template&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas template render &amp;lt;id&amp;gt; --data '{}'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Preview rendered output&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas template render-html --body H --engine mustache --data '{}'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Render inline HTML&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Rendering a preview before sending
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nylas template render &amp;lt;template-id&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s1"&gt;'{"name": "Bob", "company": "Acme", "link": "https://example.com/onboard"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Outputs the fully-rendered HTML so you can verify before sending.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sending with a template
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nylas email send &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--to&lt;/span&gt; customer@example.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--template-id&lt;/span&gt; &amp;lt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--template-data&lt;/span&gt; &lt;span class="s1"&gt;'{"name": "Alice", "invoice_url": "https://..."}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The subject line and body variables are both interpolated from the data JSON.&lt;/p&gt;

&lt;h2&gt;
  
  
  Local templates vs hosted templates
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Local (&lt;code&gt;nylas email templates&lt;/code&gt;)&lt;/th&gt;
&lt;th&gt;Hosted (&lt;code&gt;nylas template&lt;/code&gt;)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Storage&lt;/td&gt;
&lt;td&gt;On-disk files&lt;/td&gt;
&lt;td&gt;Nylas API (cloud)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sharing&lt;/td&gt;
&lt;td&gt;Per-machine&lt;/td&gt;
&lt;td&gt;Per-application (all users)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Variables&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;{{var}}&lt;/code&gt; in file&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;{{var}}&lt;/code&gt; via API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best for&lt;/td&gt;
&lt;td&gt;Personal scripts&lt;/td&gt;
&lt;td&gt;Team/product emails&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Related posts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/qasim157/build-a-daily-email-digest-with-cron-and-6-lines-of-bash-4ah1"&gt;Build a daily email digest with cron&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/qasim157/send-email-from-any-linux-server-in-60-seconds-no-smtp-config-11ac"&gt;Send email from any Linux server in 60 seconds&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;All commands:&lt;/strong&gt; &lt;a href="https://cli.nylas.com/docs/commands" rel="noopener noreferrer"&gt;Nylas CLI Command Reference&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Get started:&lt;/strong&gt; &lt;code&gt;brew install nylas/nylas-cli/nylas&lt;/code&gt; — &lt;a href="https://cli.nylas.com/guides/getting-started" rel="noopener noreferrer"&gt;other install methods&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cli</category>
      <category>email</category>
      <category>automation</category>
      <category>templates</category>
    </item>
    <item>
      <title>Manage Booking Pages and Appointments from the Terminal</title>
      <dc:creator>Qasim Muhammad</dc:creator>
      <pubDate>Sun, 10 May 2026 16:48:29 +0000</pubDate>
      <link>https://forem.com/qasim157/manage-booking-pages-and-appointments-from-the-terminal-9hb</link>
      <guid>https://forem.com/qasim157/manage-booking-pages-and-appointments-from-the-terminal-9hb</guid>
      <description>&lt;p&gt;The &lt;code&gt;nylas scheduler\&lt;/code&gt; commands manage booking pages, configurations, and appointments without touching a web dashboard. Create scheduling links, confirm bookings, handle reschedules — all from the terminal.&lt;/p&gt;

&lt;h2&gt;
  
  
  What nylas scheduler does
&lt;/h2&gt;

&lt;p&gt;Manages the full booking lifecycle: create scheduling pages with availability rules, accept bookings, confirm or cancel them, and track sessions. Replaces Calendly-style web UIs for developers who prefer CLI workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Start
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;\&lt;/code&gt;&lt;code&gt;bash&lt;br&gt;
brew install nylas/nylas-cli/nylas&lt;br&gt;
nylas init&lt;br&gt;
nylas scheduler pages list&lt;br&gt;
\&lt;/code&gt;&lt;code&gt;\&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Key commands
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas scheduler pages list\&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List scheduling pages&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas scheduler pages create\&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create a new booking page&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas scheduler pages show &amp;lt;id&amp;gt;\&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;View page details&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas scheduler bookings list\&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List all bookings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas scheduler bookings confirm &amp;lt;id&amp;gt;\&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Confirm a pending booking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas scheduler bookings reschedule &amp;lt;id&amp;gt;\&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Reschedule a booking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas scheduler bookings cancel &amp;lt;id&amp;gt;\&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cancel a booking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas scheduler configurations list\&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List scheduling configurations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas scheduler configurations create\&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create availability rules&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Creating a booking page
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;\&lt;/code&gt;&lt;code&gt;bash&lt;br&gt;
nylas scheduler pages create \\&lt;br&gt;
  --name "30-min intro call" \\&lt;br&gt;
  --duration 30 \\&lt;br&gt;
  --json&lt;br&gt;
\&lt;/code&gt;&lt;code&gt;\&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Returns a booking URL you can share. The page respects your calendar availability automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Confirming a booking
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;\&lt;/code&gt;&lt;code&gt;bash&lt;br&gt;
nylas scheduler bookings list --status pending --json&lt;br&gt;
nylas scheduler bookings confirm &amp;lt;booking-id&amp;gt;&lt;br&gt;
\&lt;/code&gt;&lt;code&gt;\&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Rescheduling
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;\&lt;/code&gt;&lt;code&gt;bash&lt;br&gt;
nylas scheduler bookings reschedule &amp;lt;booking-id&amp;gt; \\&lt;br&gt;
  --start "2026-05-15T10:00:00-05:00" \\&lt;br&gt;
  --end "2026-05-15T10:30:00-05:00"&lt;br&gt;
\&lt;/code&gt;&lt;code&gt;\&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Related posts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/qasim157/automate-meeting-scheduling-with-openclaw-and-nylas-535f"&gt;Automate Meeting Scheduling with OpenClaw&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/qasim157/manage-google-calendar-outlook-exchange-from-the-command-line-ai-scheduling-included-f12"&gt;Manage Google Calendar, Outlook &amp;amp; Exchange from the Command Line&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;All commands:&lt;/strong&gt; &lt;a href="https://cli.nylas.com/docs/commands" rel="noopener noreferrer"&gt;Nylas CLI Command Reference&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Get started:&lt;/strong&gt; &lt;code&gt;brew install nylas/nylas-cli/nylas\&lt;/code&gt; — &lt;a href="https://cli.nylas.com/guides/getting-started" rel="noopener noreferrer"&gt;other install methods&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cli</category>
      <category>scheduling</category>
      <category>calendar</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Extract OTP Codes from Email in One Command — No Inbox Browsing</title>
      <dc:creator>Qasim Muhammad</dc:creator>
      <pubDate>Sun, 10 May 2026 16:47:54 +0000</pubDate>
      <link>https://forem.com/qasim157/extract-otp-codes-from-email-in-one-command-no-inbox-browsing-4j26</link>
      <guid>https://forem.com/qasim157/extract-otp-codes-from-email-in-one-command-no-inbox-browsing-4j26</guid>
      <description>&lt;p&gt;The &lt;code&gt;nylas otp&lt;/code&gt; commands extract one-time passwords from your email automatically. Stop switching to your inbox to copy 6-digit codes — the CLI finds them and copies to your clipboard in under 3 seconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  What nylas otp does
&lt;/h2&gt;

&lt;p&gt;Scans recent emails for verification codes (6-digit, 8-digit, alphanumeric), extracts them using pattern matching, and copies the latest to your clipboard. Works with Gmail, Outlook, Yahoo, and any IMAP provider.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Start
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;nylas/nylas-cli/nylas
nylas init
nylas otp get
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it — the latest OTP code is now in your clipboard. Paste it into the verification form.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key commands
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas otp get&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Get latest OTP, copy to clipboard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas otp get --raw&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Output only the code (for scripting)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas otp watch&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Watch for new codes in real-time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas otp watch --interval 5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Poll every 5 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas otp list&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List configured accounts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas otp messages&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show recent messages with OTP detection&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Use in Playwright/Cypress tests
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In your E2E test script:&lt;/span&gt;
&lt;span class="nv"&gt;OTP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;nylas otp get &lt;span class="nt"&gt;--raw&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;# Use $OTP to fill the verification form programmatically&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This eliminates the need for Gmail API credentials in CI/CD pipelines. The CLI handles auth — your test just calls &lt;code&gt;nylas otp get --raw&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Watching for codes in real-time
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nylas otp watch &lt;span class="nt"&gt;--interval&lt;/span&gt; 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Polls every 3 seconds and prints new codes as they arrive. Useful when you triggered a "send verification code" flow and are waiting for delivery.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common issues
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;No OTP found&lt;/strong&gt;&lt;br&gt;
The code might not have arrived yet. Use &lt;code&gt;nylas otp watch&lt;/code&gt; to wait, or check &lt;code&gt;nylas otp messages&lt;/code&gt; to see what emails were scanned.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wrong code extracted&lt;/strong&gt;&lt;br&gt;
If multiple verification emails arrived recently, &lt;code&gt;nylas otp get&lt;/code&gt; returns the newest. Use &lt;code&gt;nylas otp messages&lt;/code&gt; to see all candidates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related posts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/qasim157/extract-otp-codes-from-email-skip-the-inbox-2746"&gt;Extract OTP Codes from Email — Skip the Inbox&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/qasim157/e2e-email-testing-with-playwright-and-cypress-no-gmail-credentials-required-33ig"&gt;E2E Email Testing with Playwright and Cypress&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/qasim157/per-pr-ephemeral-email-inboxes-for-e2e-tests-in-github-actions-352j"&gt;Per-PR ephemeral email inboxes for E2E tests&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;All commands:&lt;/strong&gt; &lt;a href="https://cli.nylas.com/docs/commands" rel="noopener noreferrer"&gt;Nylas CLI Command Reference&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Get started:&lt;/strong&gt; &lt;code&gt;brew install nylas/nylas-cli/nylas&lt;/code&gt; — &lt;a href="https://cli.nylas.com/guides/getting-started" rel="noopener noreferrer"&gt;other install methods&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cli</category>
      <category>email</category>
      <category>otp</category>
      <category>automation</category>
    </item>
    <item>
      <title>Record and Transcribe Zoom, Meet, and Teams Meetings from the CLI</title>
      <dc:creator>Qasim Muhammad</dc:creator>
      <pubDate>Sun, 10 May 2026 16:47:52 +0000</pubDate>
      <link>https://forem.com/qasim157/record-and-transcribe-zoom-meet-and-teams-meetings-from-the-cli-55pe</link>
      <guid>https://forem.com/qasim157/record-and-transcribe-zoom-meet-and-teams-meetings-from-the-cli-55pe</guid>
      <description>&lt;p&gt;The Nylas Notetaker is an AI bot that joins your video meetings, records audio/video, and produces a transcript. You control it from the terminal — no browser dashboard needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  What nylas notetaker does
&lt;/h2&gt;

&lt;p&gt;The notetaker bot joins Zoom, Google Meet, or Microsoft Teams calls on your behalf. It records the meeting, generates a transcript, and stores both as downloadable media. One command to start, one to retrieve the output.&lt;/p&gt;

&lt;p&gt;Supports 3 platforms (Zoom, Meet, Teams), produces transcripts in under 5 minutes post-meeting, and stores recordings for 7 days by default.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Start
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;nylas/nylas-cli/nylas
nylas init
nylas notetaker create &lt;span class="nt"&gt;--meeting-link&lt;/span&gt; https://zoom.us/j/123456
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Key commands
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas notetaker list&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List all notetakers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas notetaker create --meeting-link URL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Send a bot to record a meeting&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas notetaker create --meeting-link URL --join-time "tomorrow 2pm"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Schedule a future recording&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas notetaker show &amp;lt;id&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Check recording status&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas notetaker media &amp;lt;id&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Get recording + transcript URLs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas notetaker delete &amp;lt;id&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cancel or remove a notetaker&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Scheduling a recording for tomorrow
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nylas notetaker create &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--meeting-link&lt;/span&gt; &lt;span class="s2"&gt;"https://meet.google.com/abc-defg-hij"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--join-time&lt;/span&gt; &lt;span class="s2"&gt;"2026-05-12T14:00:00-05:00"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The bot joins at the specified time. No manual intervention needed. If the meeting hasn't started, the bot waits up to 10 minutes before timing out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retrieving the transcript
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nylas notetaker media &amp;lt;notetaker-id&amp;gt; &lt;span class="nt"&gt;--json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Returns URLs for the video recording and text transcript. Pipe to jq for automation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nylas notetaker media &amp;lt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;--json&lt;/span&gt; | jq &lt;span class="s1"&gt;'.transcript_url'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Common issues
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Bot doesn't join the meeting&lt;/strong&gt;&lt;br&gt;
Check that the meeting link is a valid Zoom, Meet, or Teams URL. The bot requires the meeting to be in progress or starting within 10 minutes of the join time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Transcript is empty&lt;/strong&gt;&lt;br&gt;
The meeting may have been too short (under 30 seconds) or the audio quality was too low for transcription.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related posts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/qasim157/5-nylas-cli-commands-every-ai-agent-should-have-access-to-2e87"&gt;5 Nylas CLI commands every AI agent should have&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/qasim157/manage-google-calendar-outlook-exchange-from-the-command-line-ai-scheduling-included-f12"&gt;Manage Google Calendar, Outlook &amp;amp; Exchange from the Command Line&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;All commands:&lt;/strong&gt; &lt;a href="https://cli.nylas.com/docs/commands" rel="noopener noreferrer"&gt;Nylas CLI Command Reference&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Get started:&lt;/strong&gt; &lt;code&gt;brew install nylas/nylas-cli/nylas&lt;/code&gt; — &lt;a href="https://cli.nylas.com/guides/getting-started" rel="noopener noreferrer"&gt;other install methods&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cli</category>
      <category>meetings</category>
      <category>ai</category>
      <category>productivity</category>
    </item>
    <item>
      <title>5 Nylas CLI commands every AI agent should have access to</title>
      <dc:creator>Qasim Muhammad</dc:creator>
      <pubDate>Mon, 04 May 2026 21:11:14 +0000</pubDate>
      <link>https://forem.com/qasim157/5-nylas-cli-commands-every-ai-agent-should-have-access-to-2e87</link>
      <guid>https://forem.com/qasim157/5-nylas-cli-commands-every-ai-agent-should-have-access-to-2e87</guid>
      <description>&lt;p&gt;Adding email and calendar tools to an AI agent is mostly an exercise in restraint. Give it 50 commands and the agent gets confused. Give it 5 carefully-chosen ones and it punches above its weight.&lt;/p&gt;

&lt;p&gt;After running agents against the Nylas CLI for a few months, these are the five I keep coming back to. Each gets exposed via MCP (&lt;a href="https://cli.nylas.com/docs/commands/mcp-install" rel="noopener noreferrer"&gt;&lt;code&gt;nylas mcp install&lt;/code&gt;&lt;/a&gt;) so the agent can call them directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. &lt;a href="https://cli.nylas.com/docs/commands/email-send" rel="noopener noreferrer"&gt;&lt;code&gt;nylas email send&lt;/code&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The most-used tool by a wide margin.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nylas email send &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--to&lt;/span&gt; alice@example.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--subject&lt;/span&gt; &lt;span class="s2"&gt;"Re: budget review"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--body&lt;/span&gt; &lt;span class="s2"&gt;"Approved. See you Friday."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why it ranks first: every agent task that touches the outside world eventually needs to communicate the result. A pull request shipped, an order placed, a bug filed — someone wants to know. Email is the lowest-common-denominator channel.&lt;/p&gt;

&lt;p&gt;Agent prompt pattern that works:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When you complete a task that affects another person, send them an email summary. Use &lt;code&gt;nylas email send&lt;/code&gt; with their address from the ticket. Subject line should match the ticket title. Body should be 2-3 sentences max.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  2. &lt;a href="https://cli.nylas.com/docs/commands/email-list" rel="noopener noreferrer"&gt;&lt;code&gt;nylas email list&lt;/code&gt;&lt;/a&gt; &lt;code&gt;--json&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Reading is half of email. The &lt;code&gt;--json&lt;/code&gt; flag matters: agents parse JSON, not prose tables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nylas email list &lt;span class="nt"&gt;--unread&lt;/span&gt; &lt;span class="nt"&gt;--limit&lt;/span&gt; 20 &lt;span class="nt"&gt;--json&lt;/span&gt; | jq &lt;span class="s1"&gt;'.[] | {from: .from[0].email, subject, snippet}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Filters that matter most:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--unread&lt;/code&gt; — only what is new&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--from "alice@example.com"&lt;/code&gt; — scope to a sender&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--query "invoice"&lt;/code&gt; — text search across subject + body&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--in folder/Inbox&lt;/code&gt; — provider-specific folders&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A common pattern: every 5 minutes, the agent runs &lt;code&gt;nylas email list --unread --json&lt;/code&gt;, sees 0-5 new messages, and decides whether each needs human attention.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. &lt;a href="https://cli.nylas.com/docs/commands/calendar-events-list" rel="noopener noreferrer"&gt;&lt;code&gt;nylas calendar events list&lt;/code&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Most "schedule a meeting" requests fail because the agent does not know what is already on the calendar. Give it visibility.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nylas calendar events list &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--start&lt;/span&gt; &lt;span class="s2"&gt;"2026-05-04T00:00:00Z"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--end&lt;/span&gt; &lt;span class="s2"&gt;"2026-05-11T00:00:00Z"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This returns a week of events as JSON the agent can reason over. Pair with &lt;a href="https://cli.nylas.com/docs/commands/calendar-find-time" rel="noopener noreferrer"&gt;&lt;code&gt;nylas calendar find-time&lt;/code&gt;&lt;/a&gt; for "find a 30-minute slot when alice@ and bob@ are both free":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nylas calendar find-time &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--participants&lt;/span&gt; alice@example.com,bob@example.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--duration&lt;/span&gt; 30 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--window-start&lt;/span&gt; &lt;span class="s2"&gt;"2026-05-04T09:00:00-05:00"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--window-end&lt;/span&gt; &lt;span class="s2"&gt;"2026-05-08T17:00:00-05:00"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. &lt;a href="https://cli.nylas.com/docs/commands/contacts-search" rel="noopener noreferrer"&gt;&lt;code&gt;nylas contacts search&lt;/code&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;This one surprised me. The agent constantly needs the answer to "what is the email of the person whose name is X". Without contacts access, it asks the user. With contacts access, it just looks up.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nylas contacts search &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s2"&gt;"alice"&lt;/span&gt; &lt;span class="nt"&gt;--json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Returns matches against name, email, and company. Three-letter queries work; the search is fuzzy.&lt;/p&gt;

&lt;p&gt;A specific pattern that pays off: when the agent drafts an email, it can run a contacts lookup on every name mentioned in the body to verify it has the right email. "Email Alice about the launch" without a contacts tool means asking which Alice. With the tool, the agent disambiguates by company or role.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. &lt;a href="https://cli.nylas.com/docs/commands/agent-account-create" rel="noopener noreferrer"&gt;&lt;code&gt;nylas agent account create&lt;/code&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;For tasks that involve a &lt;em&gt;new&lt;/em&gt; identity (testing flows, signing up for services, isolating per-PR test inboxes), the agent should be able to provision its own.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nylas agent account create test-&lt;span class="si"&gt;$(&lt;/span&gt;uuidgen&lt;span class="si"&gt;)&lt;/span&gt;@yourapp.nylas.email &lt;span class="nt"&gt;--json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pair with &lt;a href="https://cli.nylas.com/docs/commands/agent-account-delete" rel="noopener noreferrer"&gt;&lt;code&gt;nylas agent account delete&lt;/code&gt;&lt;/a&gt; to keep things tidy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nylas agent account delete &lt;span class="nv"&gt;$GRANT_ID&lt;/span&gt; &lt;span class="nt"&gt;--yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the meta-tool. The agent can spawn one-shot inboxes for E2E tests, signup automation, or cross-account verification. Most other "AI agents and email" stacks miss this primitive.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I deliberately left off
&lt;/h2&gt;

&lt;p&gt;Five more commands that are great but did not make the cut for a default agent install:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Why excluded&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://cli.nylas.com/docs/commands/email-mark-starred" rel="noopener noreferrer"&gt;&lt;code&gt;nylas email mark-starred&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Personal preference; agent has no opinion about importance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://cli.nylas.com/docs/commands/email-delete" rel="noopener noreferrer"&gt;&lt;code&gt;nylas email delete&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Destructive; require human confirmation by default&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://cli.nylas.com/docs/commands/calendar-events-create" rel="noopener noreferrer"&gt;&lt;code&gt;nylas calendar events create&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Powerful but easy to misuse — most teams want a human in the loop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://cli.nylas.com/docs/commands/webhook-create" rel="noopener noreferrer"&gt;&lt;code&gt;nylas webhook create&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Better as a one-time setup by the operator, not an agent action&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nylas agent rule create&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Same — policy and rules are operator-level config&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A safer agent surface is a smaller surface. Add commands as the agent earns trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to install just these five
&lt;/h2&gt;

&lt;p&gt;When the MCP install gives you the full tool set and you want to scope it down:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;In&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;your&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;AI&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;tool's&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;MCP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;config,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;after&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;running&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;`nylas&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;mcp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;install`&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"nylas"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"nylas"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"mcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"serve"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"NYLAS_MCP_TOOLS"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"email_send,email_list,calendar_events_list,contacts_search,agent_account_create"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;NYLAS_MCP_TOOLS&lt;/code&gt; env var allow-lists which tools the server exposes. Everything else stays hidden from the agent.&lt;/p&gt;

&lt;h2&gt;
  
  
  The takeaway
&lt;/h2&gt;

&lt;p&gt;The single biggest mistake I see in agent installs: throwing every available tool at the agent and hoping it picks. Better to start with five well-chosen ones and add more as the workflow demands. Send, list, calendar, contacts, agent-account — the five that cover 90% of real agent tasks involving email.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://cli.nylas.com/guides/give-ai-agent-email-address" rel="noopener noreferrer"&gt;Give your AI coding agent an email address&lt;/a&gt; — full MCP install for Claude Code, Cursor, Codex&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cli.nylas.com/guides/ai-agent-email-mcp" rel="noopener noreferrer"&gt;AI agent email MCP&lt;/a&gt; — MCP-specific setup walkthrough&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cli.nylas.com/guides/build-email-agent-cli" rel="noopener noreferrer"&gt;Build an LLM agent with email and calendar tools&lt;/a&gt; — broader pattern reference&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cli.nylas.com/docs/commands" rel="noopener noreferrer"&gt;Full command reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Command deep-dives for the five above:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://cli.nylas.com/docs/commands/email-send" rel="noopener noreferrer"&gt;&lt;code&gt;nylas email send&lt;/code&gt; reference&lt;/a&gt; — flags, scheduling, GPG, tracking&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cli.nylas.com/docs/commands/email-list" rel="noopener noreferrer"&gt;&lt;code&gt;nylas email list&lt;/code&gt; reference&lt;/a&gt; — filters, JSON output, pagination&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cli.nylas.com/docs/commands/calendar-events-list" rel="noopener noreferrer"&gt;&lt;code&gt;nylas calendar events list&lt;/code&gt; reference&lt;/a&gt; — date ranges, timezone handling&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cli.nylas.com/docs/commands/contacts-search" rel="noopener noreferrer"&gt;&lt;code&gt;nylas contacts search&lt;/code&gt; reference&lt;/a&gt; — fuzzy matching, JSON output&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cli.nylas.com/docs/commands/agent-account-create" rel="noopener noreferrer"&gt;&lt;code&gt;nylas agent account create&lt;/code&gt; reference&lt;/a&gt; — managed identities, policies&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Related posts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/qasim157/i-gave-my-claude-code-agent-an-email-address-14hc"&gt;I gave my Claude Code agent an email address&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/qasim157/from-gmail-oauth-hell-to-one-line-agent-identity-cpp"&gt;From Gmail OAuth hell to one-line agent identity&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aiagents</category>
      <category>mcp</category>
      <category>cli</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Send email from any Linux server in 60 seconds — no SMTP config</title>
      <dc:creator>Qasim Muhammad</dc:creator>
      <pubDate>Mon, 04 May 2026 21:11:05 +0000</pubDate>
      <link>https://forem.com/qasim157/send-email-from-any-linux-server-in-60-seconds-no-smtp-config-11ac</link>
      <guid>https://forem.com/qasim157/send-email-from-any-linux-server-in-60-seconds-no-smtp-config-11ac</guid>
      <description>&lt;p&gt;You ssh'd into a fresh Linux box and you need to send an email. Maybe a backup completed. Maybe a deploy succeeded. Maybe a process crashed and you want a stack trace in your inbox.&lt;/p&gt;

&lt;p&gt;The traditional path: install Postfix, edit &lt;code&gt;main.cf&lt;/code&gt;, configure a smart relay, generate SASL credentials, restart the daemon, and pray nothing else on the box uses port 25. That is the 30-minute path.&lt;/p&gt;

&lt;p&gt;The 60-second path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://cli.nylas.com/install.sh | bash
~/.config/nylas/bin/nylas auth config &lt;span class="nt"&gt;--api-key&lt;/span&gt; YOUR_KEY
~/.config/nylas/bin/nylas email send &lt;span class="nt"&gt;--to&lt;/span&gt; you@example.com &lt;span class="nt"&gt;--subject&lt;/span&gt; hi &lt;span class="nt"&gt;--body&lt;/span&gt; &lt;span class="s2"&gt;"From &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three lines. Zero daemon. Works on every modern Linux distro and macOS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the old path is so slow
&lt;/h2&gt;

&lt;p&gt;Setting up outbound SMTP from scratch involves five separate concerns:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concern&lt;/th&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;th&gt;Failure mode&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Install Postfix or Exim&lt;/td&gt;
&lt;td&gt;2 min&lt;/td&gt;
&lt;td&gt;Distro package conflicts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Configure relayhost&lt;/td&gt;
&lt;td&gt;5 min&lt;/td&gt;
&lt;td&gt;Wrong port, blocked by ISP, DNS lookup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SASL auth to relay&lt;/td&gt;
&lt;td&gt;10 min&lt;/td&gt;
&lt;td&gt;Hashing format, postmap regen&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TLS to relay&lt;/td&gt;
&lt;td&gt;5 min&lt;/td&gt;
&lt;td&gt;Cert path, CA bundle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Test send through queue&lt;/td&gt;
&lt;td&gt;5 min&lt;/td&gt;
&lt;td&gt;mqueue stuck, tail &lt;code&gt;/var/log/mail.log&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Five places to get it wrong. Most people get it wrong twice before it works.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the 60-second path skips
&lt;/h2&gt;

&lt;p&gt;The CLI ships a static binary. No package dependencies, no system services, no firewall punches. The send happens over HTTPS to the Nylas API on port 443 — already open in 99% of environments.&lt;/p&gt;

&lt;p&gt;Specifically, you are &lt;em&gt;not&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Opening port 25 outbound (most cloud providers block this)&lt;/li&gt;
&lt;li&gt;Setting up STARTTLS to a relay&lt;/li&gt;
&lt;li&gt;Maintaining sender DKIM/SPF/DMARC keys (the API handles signing)&lt;/li&gt;
&lt;li&gt;Writing config files in &lt;code&gt;/etc/postfix&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Real-world recipes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Cron job that emails on failure
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; /usr/local/bin/run-backup.sh&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;exit &lt;/span&gt;0
&lt;span class="k"&gt;fi

&lt;/span&gt;nylas email send &lt;span class="nt"&gt;--to&lt;/span&gt; oncall@yourcompany.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--subject&lt;/span&gt; &lt;span class="s2"&gt;"[FAIL] backup on &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--body&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;: backup failed. See /var/log/backup.log"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  systemd OnFailure handler
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="c"&gt;# /etc/systemd/system/notify-failure@.service
&lt;/span&gt;&lt;span class="nn"&gt;[Unit]&lt;/span&gt;
&lt;span class="py"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;Notify on service failure for %i&lt;/span&gt;

&lt;span class="nn"&gt;[Service]&lt;/span&gt;
&lt;span class="py"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;oneshot&lt;/span&gt;
&lt;span class="py"&gt;ExecStart&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/usr/local/bin/nylas email send --to oncall@yourcompany.com &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;  &lt;span class="s"&gt;--subject "[%H] %i failed" &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;  &lt;span class="s"&gt;--body "Check journalctl -u %i for details"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="c"&gt;# In any service that should notify on failure:
&lt;/span&gt;&lt;span class="nn"&gt;[Unit]&lt;/span&gt;
&lt;span class="py"&gt;OnFailure&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;notify-failure@%n.service&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is exactly the pattern the systemd man pages document for OnFailure, with one less moving part.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploy notification from CI
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nylas email send &lt;span class="nt"&gt;--to&lt;/span&gt; team@yourcompany.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--subject&lt;/span&gt; &lt;span class="s2"&gt;"✅ Deploy v&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; to prod"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--body&lt;/span&gt; &lt;span class="s2"&gt;"https://app.example.com/deploys/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEPLOY_ID&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Shell trap on script exit
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;trap&lt;/span&gt; &lt;span class="s1"&gt;'nylas email send --to me@example.com --subject "rebuild done on $(hostname)" --body "exit code $?"'&lt;/span&gt; EXIT

./long-running-rebuild.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What about &lt;code&gt;mailx&lt;/code&gt;, &lt;code&gt;msmtp&lt;/code&gt;, &lt;code&gt;sendmail&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;They are venerable, and on a single machine where you already have a working relay, they are fine. Where they hurt:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;mailx&lt;/code&gt;&lt;/strong&gt; needs an MTA underneath (Postfix, Exim). Nothing changes about the SMTP setup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;msmtp&lt;/code&gt;&lt;/strong&gt; is itself an SMTP client, so you still maintain relay credentials and TLS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;sendmail&lt;/code&gt;&lt;/strong&gt; is the historical command, usually backed by Postfix.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Nylas CLI replaces all three for the "I need to send from a script" use case. There is no relay to maintain because the relay is the API.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 60-second checklist
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Install&lt;/span&gt;
curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://cli.nylas.com/install.sh | bash

&lt;span class="c"&gt;# 2. Add to PATH for the session&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.config/nylas/bin:&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# 3. Auth&lt;/span&gt;
nylas auth config &lt;span class="nt"&gt;--api-key&lt;/span&gt; YOUR_KEY

&lt;span class="c"&gt;# 4. Test&lt;/span&gt;
nylas email send &lt;span class="nt"&gt;--to&lt;/span&gt; you@example.com &lt;span class="nt"&gt;--subject&lt;/span&gt; hi &lt;span class="nt"&gt;--body&lt;/span&gt; &lt;span class="s2"&gt;"from &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# 5. Verify it landed (should be in your inbox in &amp;lt;30 sec)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If step 5 worked, you are done. Add the binary location to a system-wide PATH (e.g., symlink to &lt;code&gt;/usr/local/bin&lt;/code&gt;) if other users on the box need it.&lt;/p&gt;

&lt;h2&gt;
  
  
  A note for hardened environments
&lt;/h2&gt;

&lt;p&gt;If your server has no outbound HTTPS — air-gapped, restricted egress firewall — the CLI cannot reach the API. In that case, ship messages to an internal queue (or a relay box that does have egress) and let that machine call the CLI. The CLI itself is not the bottleneck; outbound HTTPS is.&lt;/p&gt;

&lt;p&gt;Otherwise, this is the cleanest "make this Linux box send mail" setup I have used.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://cli.nylas.com/guides/send-email-from-terminal" rel="noopener noreferrer"&gt;Send email from the terminal&lt;/a&gt; — full &lt;code&gt;nylas email send&lt;/code&gt; reference&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cli.nylas.com/guides/best-cli-email-tools-compared" rel="noopener noreferrer"&gt;Best CLI email tools compared&lt;/a&gt; — head-to-head with mutt, mailx, msmtp&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cli.nylas.com/guides/powershell-email-reports" rel="noopener noreferrer"&gt;PowerShell email reports&lt;/a&gt; — same idea on Windows&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cli.nylas.com/docs/commands" rel="noopener noreferrer"&gt;Full command reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Command references used in this guide:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://cli.nylas.com/docs/commands/email-send" rel="noopener noreferrer"&gt;&lt;code&gt;nylas email send&lt;/code&gt; — flags, scheduling, GPG, templates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cli.nylas.com/docs/commands/auth-config" rel="noopener noreferrer"&gt;&lt;code&gt;nylas auth config&lt;/code&gt; — API key and credential setup&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>linux</category>
      <category>bash</category>
      <category>devops</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>From Gmail OAuth hell to one-line agent identity</title>
      <dc:creator>Qasim Muhammad</dc:creator>
      <pubDate>Mon, 04 May 2026 21:10:57 +0000</pubDate>
      <link>https://forem.com/qasim157/from-gmail-oauth-hell-to-one-line-agent-identity-cpp</link>
      <guid>https://forem.com/qasim157/from-gmail-oauth-hell-to-one-line-agent-identity-cpp</guid>
      <description>&lt;p&gt;I tried to give an AI agent its own email account three different ways. The first two took most of an afternoon. The third took 28 seconds. This is the migration story.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attempt 1: dedicated Gmail account
&lt;/h2&gt;

&lt;p&gt;The first instinct: just create a Gmail. Free, familiar, works everywhere.&lt;/p&gt;

&lt;p&gt;Forty-five minutes in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Created a new Google account with a phone number Google would accept (the agent does not have a phone)&lt;/li&gt;
&lt;li&gt;Configured 2FA, generated an app password (Gmail no longer accepts plain passwords for IMAP)&lt;/li&gt;
&lt;li&gt;Hit the "less secure apps" wall, learned it has been retired&lt;/li&gt;
&lt;li&gt;Set up OAuth 2.0 client in Google Cloud Console&lt;/li&gt;
&lt;li&gt;Configured the consent screen, reviewed scopes, marked it "Internal"&lt;/li&gt;
&lt;li&gt;Realised Internal apps cannot be created on free Workspace, so I made it External&lt;/li&gt;
&lt;li&gt;Filled in the privacy policy URL, terms URL, app domain — for an agent&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I had not sent a single message yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attempt 2: shared Gmail with a +alias
&lt;/h2&gt;

&lt;p&gt;"Just use &lt;code&gt;me+agent@gmail.com&lt;/code&gt;" is the popular shortcut. It works for receiving (Gmail routes &lt;code&gt;+&lt;/code&gt; aliases to the same inbox), but:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The "From" address on outbound is still the parent account&lt;/li&gt;
&lt;li&gt;The agent's mail mixes with mine, so my filters break&lt;/li&gt;
&lt;li&gt;Compromise of the agent's credentials = compromise of my personal mail&lt;/li&gt;
&lt;li&gt;Audit logs cannot tell us apart&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two hours later I gave up on this path. The mixing problem is fatal once you have more than one agent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attempt 3: &lt;a href="https://cli.nylas.com/docs/commands/agent-account-create" rel="noopener noreferrer"&gt;&lt;code&gt;nylas agent account create&lt;/code&gt;&lt;/a&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;nylas agent account create coder@yourapp.nylas.email

✓ Agent account created successfully!

  Email:      coder@yourapp.nylas.email
  Provider:   nylas
  Status:     valid
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Twenty-eight seconds wall-clock. No OAuth, no Workspace seat, no shared mailbox.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is happening under the hood
&lt;/h2&gt;

&lt;p&gt;Three things, in this order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The CLI auto-creates the &lt;code&gt;nylas&lt;/code&gt; connector on your application if it does not exist. This is a one-time, idempotent setup.&lt;/li&gt;
&lt;li&gt;It provisions a managed mailbox under your application's &lt;code&gt;*.nylas.email&lt;/code&gt; zone. The mailbox lives entirely on Nylas — no Gmail, no Workspace, no third-party IMAP.&lt;/li&gt;
&lt;li&gt;It stores the new grant locally so subsequent CLI commands resolve it without an explicit &lt;code&gt;--grant&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The grant is &lt;code&gt;provider=nylas&lt;/code&gt;, which means: no OAuth handshake, no token refresh, no client-secret rotation. The identity is managed end-to-end.&lt;/p&gt;

&lt;h2&gt;
  
  
  Side-by-side comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Gmail OAuth&lt;/th&gt;
&lt;th&gt;Agent account&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Create the identity&lt;/td&gt;
&lt;td&gt;~5 min (account, 2FA, app password)&lt;/td&gt;
&lt;td&gt;One command&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Configure OAuth client&lt;/td&gt;
&lt;td&gt;~12 min (Cloud Console, scopes, consent)&lt;/td&gt;
&lt;td&gt;Not applicable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wire up auth in your app&lt;/td&gt;
&lt;td&gt;~10 min (refresh token plumbing)&lt;/td&gt;
&lt;td&gt;One &lt;a href="https://cli.nylas.com/docs/commands/auth-config" rel="noopener noreferrer"&gt;&lt;code&gt;nylas auth config&lt;/code&gt;&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Setup time total&lt;/td&gt;
&lt;td&gt;~45 min&lt;/td&gt;
&lt;td&gt;~30 sec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Per-month cost&lt;/td&gt;
&lt;td&gt;Workspace seat $6&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Token refresh&lt;/td&gt;
&lt;td&gt;Yours to manage&lt;/td&gt;
&lt;td&gt;Not applicable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-provider reach&lt;/td&gt;
&lt;td&gt;Gmail only&lt;/td&gt;
&lt;td&gt;Gmail, Outlook, Exchange, Yahoo, iCloud, IMAP, agent&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Migrating an existing agent
&lt;/h2&gt;

&lt;p&gt;If you have already wired up an agent to a Gmail account, the migration is mechanical:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Provision the agent's new identity&lt;/span&gt;
nylas agent account create coder@yourapp.nylas.email

&lt;span class="c"&gt;# 2. Optional: enable IMAP/SMTP (if your agent uses a stock library)&lt;/span&gt;
nylas agent account update coder@yourapp.nylas.email &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--app-password&lt;/span&gt; &lt;span class="s1"&gt;'ValidAgentPass123ABC!'&lt;/span&gt;

&lt;span class="c"&gt;# 3. Send a test&lt;/span&gt;
nylas email send &lt;span class="nt"&gt;--to&lt;/span&gt; you@example.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--subject&lt;/span&gt; &lt;span class="s2"&gt;"test from new agent identity"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--body&lt;/span&gt; &lt;span class="s2"&gt;"Hi from the managed inbox."&lt;/span&gt;

&lt;span class="c"&gt;# 4. Update the agent's prompt / config to use the new address&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the whole migration. The hardest part is finding everywhere the old address is hard-coded.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd warn future-me about
&lt;/h2&gt;

&lt;p&gt;Three lessons from the misadventure:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Phone number requirement&lt;/strong&gt;: Gmail's signup will demand a phone for verification. Agents do not have phones. Burn an OTP-friendly number and accept Google may flag the account later.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OAuth refresh tokens expire&lt;/strong&gt;: a Gmail OAuth refresh token is not infinite. Tokens for unverified Cloud apps expire after 7 days; production verification is its own multi-week project.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Per-seat costs scale&lt;/strong&gt;: if your team runs 5 agents, that is 5 Workspace seats at $6 each = $30/mo just to give them mail.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  When Gmail still wins
&lt;/h2&gt;

&lt;p&gt;Be honest about the trade. If the agent must read or send from an existing inbox at &lt;code&gt;@yourcompany.com&lt;/code&gt; (your real domain), and your company is on Workspace, you do not want a separate Nylas address. In that case, OAuth Gmail and pay the setup cost. The agent identity model is for &lt;em&gt;new&lt;/em&gt; agent inboxes, not for migrating your CEO's mailbox.&lt;/p&gt;

&lt;p&gt;For everything else — testing, signup automation, agent-to-agent messaging, ephemeral inboxes, managed bots — the agent account wins on every dimension I can measure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://cli.nylas.com/guides/create-ai-agent-email-identity" rel="noopener noreferrer"&gt;Create an AI agent email identity&lt;/a&gt; — the full setup walkthrough&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cli.nylas.com/guides/why-ai-agents-need-email" rel="noopener noreferrer"&gt;Why AI agents need email&lt;/a&gt; — the case before the setup&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cli.nylas.com/guides/email-as-identity-for-ai-agents" rel="noopener noreferrer"&gt;Email as identity for AI agents&lt;/a&gt; — the deeper argument about agent identity&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cli.nylas.com/docs/commands" rel="noopener noreferrer"&gt;Full command reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Command references used in this guide:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://cli.nylas.com/docs/commands/agent-account-create" rel="noopener noreferrer"&gt;&lt;code&gt;nylas agent account create&lt;/code&gt; — create a managed agent identity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cli.nylas.com/docs/commands/auth-config" rel="noopener noreferrer"&gt;&lt;code&gt;nylas auth config&lt;/code&gt; — configure API credentials&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cli.nylas.com/docs/commands/email-send" rel="noopener noreferrer"&gt;&lt;code&gt;nylas email send&lt;/code&gt; — send email from the agent address&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cli.nylas.com/docs/commands/email-list" rel="noopener noreferrer"&gt;&lt;code&gt;nylas email list&lt;/code&gt; — read incoming messages&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aiagents</category>
      <category>security</category>
      <category>devops</category>
      <category>productivity</category>
    </item>
    <item>
      <title>AI agents need email — your MCP setup is incomplete without it</title>
      <dc:creator>Qasim Muhammad</dc:creator>
      <pubDate>Mon, 04 May 2026 21:10:49 +0000</pubDate>
      <link>https://forem.com/qasim157/ai-agents-need-email-your-mcp-setup-is-incomplete-without-it-ic6</link>
      <guid>https://forem.com/qasim157/ai-agents-need-email-your-mcp-setup-is-incomplete-without-it-ic6</guid>
      <description>&lt;p&gt;Your MCP setup probably has filesystem, Slack, GitHub, maybe a database connector. Common stack. Common gap: no email.&lt;/p&gt;

&lt;p&gt;That gap is more important than most teams realise. Here is the case for fixing it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The world the agent lives in
&lt;/h2&gt;

&lt;p&gt;Imagine the agent's day from its perspective. It opens a ticket. The ticket references a customer. The customer's prior emails are in your inbox. The fix the agent ships triggers a notification email to that customer. A reply lands a few hours later. Without an inbox, the agent only sees the ticket — which is half the conversation.&lt;/p&gt;

&lt;p&gt;Email is the universal envelope. Slack and GitHub are walled gardens. Email crosses every boundary your agent's work eventually crosses: customers, partners, vendors, regulators, internal teams that are not on Slack.&lt;/p&gt;

&lt;h2&gt;
  
  
  The four flows MCP-without-email cannot handle
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Flow&lt;/th&gt;
&lt;th&gt;What goes wrong&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Account verification&lt;/td&gt;
&lt;td&gt;Service emails an OTP, agent has no inbox, signup stalls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Customer context&lt;/td&gt;
&lt;td&gt;Past correspondence with the customer is in email, agent operates blind&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Async hand-off&lt;/td&gt;
&lt;td&gt;Agent emails a vendor, vendor replies a day later, agent never sees it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compliance evidence&lt;/td&gt;
&lt;td&gt;Audit asks "what did the agent communicate", email is the record&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I hit the first one trying to give Cursor a Stripe API key. Stripe sent a confirmation email, Cursor had no way to read it, signup hung.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "agent has email" actually means
&lt;/h2&gt;

&lt;p&gt;Three capabilities, in order of value:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Read the inbox&lt;/strong&gt; — list, search, get message bodies, parse attachments&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Send mail&lt;/strong&gt; — transactional sends from a real address&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;React in real time&lt;/strong&gt; — subscribe to inbound events and run a handler&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A complete MCP setup gives the agent all three. The Nylas MCP server, installed via &lt;a href="https://cli.nylas.com/docs/commands/mcp-install" rel="noopener noreferrer"&gt;&lt;code&gt;nylas mcp install&lt;/code&gt;&lt;/a&gt;, exposes them as tools the agent can call.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup, end-to-end
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install the CLI&lt;/span&gt;
brew &lt;span class="nb"&gt;install &lt;/span&gt;nylas/nylas-cli/nylas

&lt;span class="c"&gt;# Auth with API key (no OAuth flow for the install)&lt;/span&gt;
nylas auth config &lt;span class="nt"&gt;--api-key&lt;/span&gt; YOUR_KEY

&lt;span class="c"&gt;# Provision a managed inbox the agent owns&lt;/span&gt;
nylas agent account create coder@yourapp.nylas.email

&lt;span class="c"&gt;# Install the MCP server config into Claude Desktop / Cursor / Codex&lt;/span&gt;
nylas mcp &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last command writes the right &lt;code&gt;mcp.servers&lt;/code&gt; block into the AI tool's config. Restart the tool and the agent has &lt;code&gt;nylas-email&lt;/code&gt;, &lt;code&gt;nylas-calendar&lt;/code&gt;, &lt;code&gt;nylas-contacts&lt;/code&gt; available as MCP tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changes for the agent
&lt;/h2&gt;

&lt;p&gt;After install, the agent can do things like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You: Find the last 3 emails from acme-corp@customer.com and summarise their concerns.

Agent: [calls nylas-email tool: list with filter from=acme-corp@customer.com limit=3]
[reads bodies]
Three messages from Jamie at Acme over the past week:
1. Apr 28 — initial bug report about CSV export missing rows
2. Apr 30 — follow-up after our reply, requesting RCA
3. May 2 — escalation noting it is now blocking their finance close
The thread is unresolved. Suggest replying with...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That conversation is impossible without inbox access.&lt;/p&gt;

&lt;h2&gt;
  
  
  The MCP-purist objection
&lt;/h2&gt;

&lt;p&gt;"MCP is supposed to be small composable tools. Email is too big."&lt;/p&gt;

&lt;p&gt;The Nylas MCP server is composable: each method is its own tool — &lt;code&gt;list&lt;/code&gt;, &lt;code&gt;get&lt;/code&gt;, &lt;code&gt;send&lt;/code&gt;, &lt;code&gt;mark_read&lt;/code&gt;, &lt;code&gt;mark_starred&lt;/code&gt;, &lt;code&gt;search&lt;/code&gt;, &lt;code&gt;attachments_list&lt;/code&gt;. The agent does not get a giant "do email things" black box. It gets ~12 small tools that compose like the filesystem ones.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security without ceremony
&lt;/h2&gt;

&lt;p&gt;Three controls keep the agent honest:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scoped grant&lt;/strong&gt;: the agent uses an agent-account grant (&lt;code&gt;provider=nylas&lt;/code&gt;), separate from your personal Gmail. Compromise of the agent inbox does not touch your personal mail.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Outbound rules&lt;/strong&gt;: &lt;a href="https://cli.nylas.com/docs/commands/agent-rule-create" rel="noopener noreferrer"&gt;&lt;code&gt;nylas agent rule create&lt;/code&gt;&lt;/a&gt; &lt;code&gt;--trigger outbound&lt;/code&gt; lets you cap who the agent can send to (e.g., only internal domains until you trust it).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audit log&lt;/strong&gt;: &lt;a href="https://cli.nylas.com/docs/commands/audit-logs-enable" rel="noopener noreferrer"&gt;&lt;code&gt;nylas audit logs enable&lt;/code&gt;&lt;/a&gt; records every CLI invocation with timestamp, command, and exit code. &lt;a href="https://cli.nylas.com/docs/commands/audit-export" rel="noopener noreferrer"&gt;&lt;code&gt;nylas audit export&lt;/code&gt;&lt;/a&gt; produces JSON or CSV for compliance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The audit trail in particular is a feature most MCP setups skip. When the agent sends mail on your behalf, you want a record.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not Gmail MCP
&lt;/h2&gt;

&lt;p&gt;There are MCP servers that wrap Gmail directly. They work. Three reasons I prefer the agent-account model:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Identity separation&lt;/strong&gt; — the agent has its own address, not yours. Replies stay attributable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-provider&lt;/strong&gt; — the same agent can read a Gmail inbox, an Outlook inbox, and an IMAP inbox without switching tools.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No OAuth churn&lt;/strong&gt; — &lt;code&gt;provider=nylas&lt;/code&gt; agent accounts skip the OAuth refresh dance.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you only ever touch Gmail and you are happy with the agent posting from your personal account, a Gmail MCP server is fine. If you want the agent to &lt;em&gt;be&lt;/em&gt; an entity in its own right, give it its own inbox.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to install today
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Install the Nylas CLI&lt;/li&gt;
&lt;li&gt;Provision an agent account (one command)&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;nylas mcp install&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Restart your AI tool&lt;/li&gt;
&lt;li&gt;Watch the agent stop asking you to copy-paste verification links&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That is the smallest possible upgrade with the largest workflow shift. If you skip it, your agent stays half-blind.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://cli.nylas.com/guides/ai-agent-email-mcp" rel="noopener noreferrer"&gt;AI agent email MCP&lt;/a&gt; — full MCP install walkthrough&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cli.nylas.com/guides/why-ai-agents-need-email" rel="noopener noreferrer"&gt;Why AI agents need email&lt;/a&gt; — the longer argument&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cli.nylas.com/guides/give-ai-agent-email-address" rel="noopener noreferrer"&gt;Give your AI coding agent an email address&lt;/a&gt; — Claude Code, Cursor, Codex setup&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cli.nylas.com/docs/commands" rel="noopener noreferrer"&gt;Full command reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Command references:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://cli.nylas.com/docs/commands/mcp-install" rel="noopener noreferrer"&gt;&lt;code&gt;nylas mcp install&lt;/code&gt; — connect AI assistants to email&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cli.nylas.com/docs/commands/mcp-serve" rel="noopener noreferrer"&gt;&lt;code&gt;nylas mcp serve&lt;/code&gt; — start the MCP server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cli.nylas.com/docs/commands/email-send" rel="noopener noreferrer"&gt;&lt;code&gt;nylas email send&lt;/code&gt; — send email from the agent&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cli.nylas.com/docs/commands/email-list" rel="noopener noreferrer"&gt;&lt;code&gt;nylas email list&lt;/code&gt; — read the agent inbox&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cli.nylas.com/docs/commands/agent-account-create" rel="noopener noreferrer"&gt;&lt;code&gt;nylas agent account create&lt;/code&gt; — provision an agent identity&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aiagents</category>
      <category>mcp</category>
      <category>ai</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Per-PR ephemeral email inboxes for E2E tests in GitHub Actions</title>
      <dc:creator>Qasim Muhammad</dc:creator>
      <pubDate>Mon, 04 May 2026 21:10:40 +0000</pubDate>
      <link>https://forem.com/qasim157/per-pr-ephemeral-email-inboxes-for-e2e-tests-in-github-actions-352j</link>
      <guid>https://forem.com/qasim157/per-pr-ephemeral-email-inboxes-for-e2e-tests-in-github-actions-352j</guid>
      <description>&lt;p&gt;Your password-reset flow needs an inbox to test against. Your invitation flow too. Your email-verification gate too. The classic setup is a "&lt;a href="mailto:test+pr-1234@yourdomain.com"&gt;test+pr-1234@yourdomain.com&lt;/a&gt;" alias on a shared mailbox, polling Gmail's API, hoping nothing else lands while the test runs. It is fragile, it leaks state across PRs, and your credentials live in CI.&lt;/p&gt;

&lt;p&gt;A managed agent account flips this. Each PR gets a fresh inbox, lives only for the duration of the test run, and tears itself down at the end.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this gives you
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;One inbox per PR, isolated from every other test&lt;/li&gt;
&lt;li&gt;Real send/receive — not a mock&lt;/li&gt;
&lt;li&gt;No shared Gmail credentials in CI&lt;/li&gt;
&lt;li&gt;Cleanup is one command per inbox&lt;/li&gt;
&lt;li&gt;Parallel test workers do not collide&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The full GitHub Action
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .github/workflows/e2e.yml&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;E2E with ephemeral inbox&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;e2e&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install Nylas CLI&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;curl -fsSL https://cli.nylas.com/install.sh | bash&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;NYLAS_INSTALL_DIR&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ github.workspace }}/.nylas&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Authenticate&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$NYLAS_INSTALL_DIR/bin/nylas auth config --api-key ${{ secrets.NYLAS_API_KEY }}&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Create ephemeral inbox&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;inbox&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;EMAIL="e2e-pr${{ github.event.number }}-run${{ github.run_id }}@yourapp.nylas.email"&lt;/span&gt;
          &lt;span class="s"&gt;$NYLAS_INSTALL_DIR/bin/nylas agent account create "$EMAIL" --json &amp;gt; inbox.json&lt;/span&gt;
          &lt;span class="s"&gt;echo "email=$EMAIL" &amp;gt;&amp;gt; $GITHUB_OUTPUT&lt;/span&gt;
          &lt;span class="s"&gt;echo "grant_id=$(jq -r .id inbox.json)" &amp;gt;&amp;gt; $GITHUB_OUTPUT&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run Playwright&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pnpm test:e2e&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;E2E_INBOX&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ steps.inbox.outputs.email }}&lt;/span&gt;
          &lt;span class="na"&gt;E2E_GRANT_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ steps.inbox.outputs.grant_id }}&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Tear down inbox&lt;/span&gt;
        &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always()&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$NYLAS_INSTALL_DIR/bin/nylas agent account delete ${{ steps.inbox.outputs.grant_id }} --yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;if: always()&lt;/code&gt; on teardown makes sure the inbox is removed even when tests fail.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the test reads mail
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// tests/auth.spec.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@playwright/test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;execFileSync&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node:child_process&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;password reset email lands and link works&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;inbox&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;E2E_INBOX&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;grantId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;E2E_GRANT_ID&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;

  &lt;span class="c1"&gt;// 1. Trigger password reset&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/forgot-password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[name=email]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;inbox&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button:has-text("Send reset link")&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// 2. Poll the inbox for up to 30 seconds&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;link&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;pollForResetLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;grantId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toMatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="sr"&gt;reset&lt;/span&gt;&lt;span class="se"&gt;\/[&lt;/span&gt;&lt;span class="sr"&gt;a-f0-9-&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// 3. Click the link, verify the new-password form&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="sr"&gt;reset&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;pollForResetLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;grantId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;timeoutMs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;deadline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;timeoutMs&lt;/span&gt;
  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;deadline&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;execFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;nylas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;list&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--grant&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;grantId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--unread&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--limit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;5&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;encoding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utf-8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;match&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;snippet&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/https:&lt;/span&gt;&lt;span class="se"&gt;\/\/[^\s]&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="sr"&gt;reset&lt;/span&gt;&lt;span class="se"&gt;\/[&lt;/span&gt;&lt;span class="sr"&gt;a-f0-9-&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node:child_process&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;execSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sleep 2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;reset email never arrived&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why this beats the alternatives
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Per-PR isolation&lt;/th&gt;
&lt;th&gt;No shared creds&lt;/th&gt;
&lt;th&gt;Real inbox&lt;/th&gt;
&lt;th&gt;Setup time&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Mailosaur&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;Paid SaaS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MailHog (self-hosted)&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌ (dev only)&lt;/td&gt;
&lt;td&gt;Run a daemon&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gmail "+pr-1234" alias&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;OAuth setup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Agent accounts&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;Two CLI commands&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Mailosaur is excellent and used by many teams. The trade is the SaaS contract. Agent accounts ride your existing Nylas plan.&lt;/p&gt;

&lt;h2&gt;
  
  
  Parallel workers
&lt;/h2&gt;

&lt;p&gt;GitHub Actions runs multiple PRs concurrently. Two PRs landing at the same time would clobber a shared inbox. Per-PR provisioning makes that a non-issue:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PR #1234 → &lt;code&gt;e2e-pr1234-run-9999@yourapp.nylas.email&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;PR #1235 → &lt;code&gt;e2e-pr1235-run-1000@yourapp.nylas.email&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you parallelise inside a single PR (e.g., &lt;code&gt;matrix&lt;/code&gt; strategy), include the matrix index in the email:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;matrix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;shard&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;2&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;3&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;4&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;EMAIL="e2e-pr${{ github.event.number }}-shard${{ matrix.shard }}@yourapp.nylas.email"&lt;/span&gt;
      &lt;span class="s"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Cost notes
&lt;/h2&gt;

&lt;p&gt;Each agent account is one grant. Most plans bill on grants, so a 50-PR-a-week rate is 50 grants created and destroyed weekly. Cleanup is mandatory or you accumulate dead accounts. The &lt;code&gt;if: always()&lt;/code&gt; step above takes care of that.&lt;/p&gt;

&lt;h2&gt;
  
  
  A real-world catch I hit
&lt;/h2&gt;

&lt;p&gt;GitHub Actions runners do not have &lt;code&gt;nylas&lt;/code&gt; on PATH after &lt;code&gt;curl install.sh | bash&lt;/code&gt; — the binary is at &lt;code&gt;$NYLAS_INSTALL_DIR/bin&lt;/code&gt;. Either add to PATH explicitly or invoke with the full path, as in the workflow above. I forgot this twice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://cli.nylas.com/guides/e2e-email-testing" rel="noopener noreferrer"&gt;E2E email testing with Playwright&lt;/a&gt; — the hands-on guide for password-reset and verification flows&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cli.nylas.com/guides/receive-inbound-email-cli" rel="noopener noreferrer"&gt;Receive email without an SMTP server&lt;/a&gt; — production agent-account patterns&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cli.nylas.com/guides/create-ai-agent-email-identity" rel="noopener noreferrer"&gt;Create an AI agent email identity&lt;/a&gt; — full agent account walkthrough&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cli.nylas.com/docs/commands" rel="noopener noreferrer"&gt;Full command reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>testing</category>
      <category>devops</category>
      <category>tutorial</category>
      <category>automation</category>
    </item>
  </channel>
</rss>
