<?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>DEV Community: Elastic Email</title>
    <description>The latest articles on DEV Community by Elastic Email (@elasticemail).</description>
    <link>https://dev.to/elasticemail</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4109501%2Ff2e4c5cc-2055-4ebe-b860-79db68297061.png</url>
      <title>DEV Community: Elastic Email</title>
      <link>https://dev.to/elasticemail</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/elasticemail"/>
    <language>en</language>
    <item>
      <title>How to Send Email from Cloudflare Workers, Vercel Edge &amp; Supabase Edge with the Elastic Email SDK + 12 Serverless Examples</title>
      <dc:creator>Elastic Email</dc:creator>
      <pubDate>Thu, 08 Oct 2026 10:09:53 +0000</pubDate>
      <link>https://dev.to/elasticemail/how-to-send-email-from-cloudflare-workers-vercel-edge-supabase-edge-with-the-elastic-email-sdk--33p</link>
      <guid>https://dev.to/elasticemail/how-to-send-email-from-cloudflare-workers-vercel-edge-supabase-edge-with-the-elastic-email-sdk--33p</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv0ndneyraz7xo6miv8ki.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv0ndneyraz7xo6miv8ki.png" alt="![Elastic Email real-world email integration examples for developers and AI agents](...)" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Sending email from a serverless function with the Elastic Email SDK is the same call you'd make on Node, with one exception.&lt;/strong&gt; On edge runtimes (Cloudflare Workers, Vercel Edge, Netlify Edge, Deno Deploy, Supabase Edge Functions) you pass a fetch-based axios instance as the third argument to &lt;code&gt;EmailsApi&lt;/code&gt;, because those runtimes have no &lt;code&gt;node:http&lt;/code&gt;. The working code for 12 platforms lives in one MIT-licensed folder, and every project exposes the same three endpoints.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why does the SDK fail on edge runtimes?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;@elasticemail/elasticemail-client-ts-axios&lt;/code&gt; is built on axios, and axios reaches for Node's &lt;code&gt;http&lt;/code&gt; adapter unless told otherwise. Cloudflare Workers, Vercel Edge, Netlify Edge, Deno Deploy, and Supabase Edge Functions don't ship &lt;code&gt;node:http&lt;/code&gt;, so the first call fails at bundle time or at runtime, depending on your bundler. On Node runtimes (AWS Lambda, Railway, Encore, Vercel's Node functions, Firebase, Azure Functions, Cloud Run, Convex Node actions) the default adapter is fine.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix: one argument
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;axios&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&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;Configuration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;EmailsApi&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="s2"&gt;@elasticemail/elasticemail-client-ts-axios&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;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&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;ELASTICEMAIL_API_KEY&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Only needed on runtimes without node:http&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;emailsApi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;EmailsApi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fetch&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;emailsApi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emailsTransactionalPost&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;Recipients&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;To&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;Content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;From&lt;/span&gt;&lt;span class="p"&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;EMAIL_FROM&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// must be on a domain verified in Elastic Email&lt;/span&gt;
    &lt;span class="na"&gt;Subject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;ContentType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;HTML&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;Content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;p&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/p&amp;gt;`&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// data.TransactionID, data.MessageID&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Keep your top-level axios dependency on the same range the SDK uses (&lt;code&gt;~1.18.0&lt;/code&gt;) so npm dedupes it. Two copies of axios in the tree are the second most common reason a serverless send fails.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Deploy to Cloudflare Workers
&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;cd &lt;/span&gt;cloudflare-workers
npm &lt;span class="nb"&gt;install
&lt;/span&gt;wrangler login
wrangler secret put ELASTICEMAIL_API_KEY
wrangler secret put ELASTICEMAIL_WEBHOOK_TOKEN
npm run deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;On Workers, environment variables are not globals. They arrive as the second argument of &lt;code&gt;fetch(request, env)&lt;/code&gt;, so the example builds &lt;code&gt;EmailsApi&lt;/code&gt; per request. &lt;code&gt;nodejs_compat&lt;/code&gt; is enabled in &lt;code&gt;wrangler.toml&lt;/code&gt; so axios' Node imports resolve at bundle time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Test it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nv"&gt;$URL&lt;/span&gt;/health
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="nv"&gt;$URL&lt;/span&gt;/send &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"to":"you@yourdomain.com","subject":"Hello","message":"Hi from the edge!"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Register the webhook after you deploy.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When you save a webhook, Elastic Email sends one test event to the URL and only saves the webhook if it gets a &lt;code&gt;2xx&lt;/code&gt;, so deploy first. Requests are not signed; the examples append a shared token to the callback URL and verify it with a constant-time comparison. Events arrive as &lt;code&gt;GET&lt;/code&gt; requests with the details in the query string (&lt;code&gt;status&lt;/code&gt;, &lt;code&gt;to&lt;/code&gt;, &lt;code&gt;transaction&lt;/code&gt;, &lt;code&gt;messageid&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  The other 11 platforms:
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;Runtime&lt;/th&gt;
&lt;th&gt;The one thing to know&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Vercel Functions&lt;/td&gt;
&lt;td&gt;Node and Edge&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;api/send.ts&lt;/code&gt; runs on Node, &lt;code&gt;api/send-edge.ts&lt;/code&gt; on Edge; files starting with &lt;code&gt;_&lt;/code&gt; are not deployed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Supabase Edge Functions&lt;/td&gt;
&lt;td&gt;Deno&lt;/td&gt;
&lt;td&gt;No npm install, functions import &lt;code&gt;npm:&lt;/code&gt; specifiers; set &lt;code&gt;verify_jwt = false&lt;/code&gt; for the webhook; an auth-hook function delivers Supabase Auth emails through Elastic Email&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS Lambda (SAM)&lt;/td&gt;
&lt;td&gt;Node&lt;/td&gt;
&lt;td&gt;The key is a &lt;code&gt;NoEcho&lt;/code&gt; CloudFormation parameter; move it to Secrets Manager or SSM for production&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deno Deploy&lt;/td&gt;
&lt;td&gt;Deno&lt;/td&gt;
&lt;td&gt;&lt;code&gt;deno task deploy&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Netlify Functions&lt;/td&gt;
&lt;td&gt;Node&lt;/td&gt;
&lt;td&gt;&lt;code&gt;netlify env:import .env&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Railway&lt;/td&gt;
&lt;td&gt;Node&lt;/td&gt;
&lt;td&gt;A long-running Hono server, not a function; binds &lt;code&gt;0.0.0.0:$PORT&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Encore.ts&lt;/td&gt;
&lt;td&gt;Node&lt;/td&gt;
&lt;td&gt;Secrets are read with &lt;code&gt;secret("ElasticEmailApiKey")()&lt;/code&gt;, not &lt;code&gt;process.env&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Firebase Cloud Functions&lt;/td&gt;
&lt;td&gt;Node&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;defineSecret&lt;/code&gt; + &lt;code&gt;.value()&lt;/code&gt;; a callable &lt;code&gt;sendEmailToMe&lt;/code&gt; for Flutter and mobile apps so the API key never ships in the app&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Azure Functions&lt;/td&gt;
&lt;td&gt;Node v4 model&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;/send&lt;/code&gt; requires the function key; the webhook stays anonymous behind &lt;code&gt;?token=&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google Cloud Run&lt;/td&gt;
&lt;td&gt;Node in a container&lt;/td&gt;
&lt;td&gt;The runtime service account needs &lt;code&gt;roles/secretmanager.secretAccessor&lt;/code&gt; on both secrets&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Convex&lt;/td&gt;
&lt;td&gt;Convex runtime + Node&lt;/td&gt;
&lt;td&gt;The SDK call lives in a &lt;code&gt;"use node"&lt;/code&gt; internal action that &lt;code&gt;convex/http.ts&lt;/code&gt; invokes with &lt;code&gt;ctx.runAction&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Do I need a verified domain to test?
&lt;/h3&gt;

&lt;p&gt;Yes. The From address must be on a domain verified in Elastic Email; publishing the SPF and DKIM records takes a few minutes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is there a free tier?
&lt;/h3&gt;

&lt;p&gt;Yes. &lt;strong&gt;100 emails a day, no credit card.&lt;/strong&gt; Every example in the repository runs on it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use SMTP instead of the SDK?
&lt;/h3&gt;

&lt;p&gt;Yes. Point your tool at &lt;code&gt;smtp.elasticemail.com&lt;/code&gt; with SMTP credentials (&lt;strong&gt;Settings &amp;gt; SMTP&lt;/strong&gt; in the dashboard, not the API key).&lt;/p&gt;

&lt;p&gt;The repo has a separate folder with &lt;strong&gt;28 SMTP integrations&lt;/strong&gt;, from Supabase Auth to WordPress to Grafana.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Repository:&lt;/strong&gt; &lt;a href="https://github.com/ElasticEmail/elasticemail-examples?utm_source=dev.to&amp;amp;utm_medium=paid_social&amp;amp;utm_campaign=serverless"&gt;github.com/ElasticEmail/elasticemail-examples&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Something missing? Issues and pull requests are open, and so are the comments below.&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>javascript</category>
      <category>email</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Official Elastic Email CLI</title>
      <dc:creator>Elastic Email</dc:creator>
      <pubDate>Wed, 09 Sep 2026 11:14:04 +0000</pubDate>
      <link>https://dev.to/elasticemail/official-elastic-email-cli-3be0</link>
      <guid>https://dev.to/elasticemail/official-elastic-email-cli-3be0</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqnd36e7bwbz9tsr3p3a9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqnd36e7bwbz9tsr3p3a9.png" alt="Terminal window running npm install -g elastic-email-cli, then auth set-key, then an emails send command, over a photo of a developer at a laptop with paper plane icons trailing from the terminal." width="800" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is our first post here, so a quick introduction. &lt;br&gt;
We build Elastic Email, a platform and API for transactional email and marketing campaigns. This week we published a CLI for it, MIT-licensed and developed in the open, and one design decision inside it is the reason we are writing this instead of a plain release note.&lt;/p&gt;

&lt;p&gt;A CLI for an API like ours gets used in two places that want opposite things.&lt;br&gt;
A person exploring an account wants color, structure, arrow keys, and a wizard that stops them from sending a campaign to the wrong list. A CI job wants parseable output, and an exit code it can branch on. Serving both usually means two tools, or one tool with a --quiet flag that everyone forgets to pass.&lt;br&gt;
So we put the decision in the CLI instead. It checks for a TTY and adapts.&lt;/p&gt;

&lt;p&gt;On a terminal, a bare elastic-email opens an interactive TUI: arrow keys through templates, lists, contacts, segments, delivery events, and sender domains, plus a guided send wizard with verified-domain hints on the sender field. The same bare command, when run in a pipe or in a CI runner, prints plain help, because a script that receives a bare invocation needs it.&lt;/p&gt;

&lt;p&gt;The rest follows from there. Every command accepts --json. Piped output drops the banner and the decorations. Exit codes are stable and specific, so a job can distinguish a missing API key from a malformed address and respond differently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Getting started&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -g elastic-email-cli
elastic-email auth set-key
elastic-email emails send --to you@example.com --subject "Hello" --text "It works!" --from me@yourdomain.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You need Node.js 20 or newer and an Elastic Email API key.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;About the API key&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The key resolves in a fixed order: the --api-key flag, then the ELASTIC_EMAIL_API_KEY environment variable, then a local config file. auth set-key writes that file in plaintext at ~/.elastic-email-cli/config.json with 0600 permission. This is convenient on a personal machine, and the environment variable is the better answer on shared machines and CI runners, which is why it takes precedence over the file. In logs and error output, the key appears only in masked form.&lt;/p&gt;

&lt;p&gt;Beyond sending, the Elastic Email CLI covers templates, contacts, lists, segments, suppressions, delivery events, address verification, sender domain (SPF, DKIM, MX, and DMARC), and account statistics. The full command reference lives in the repository. &lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/ElasticEmail/elasticemail-cli" rel="noopener noreferrer"&gt;https://github.com/ElasticEmail/elasticemail-cli&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s MIT-licensed. If a command you expected is missing, feel free to reach out to us with feedback.&lt;/p&gt;

</description>
      <category>cli</category>
      <category>emailapi</category>
      <category>showdev</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
