<?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: Mahesh</title>
    <description>The latest articles on DEV Community by Mahesh (@maheshch).</description>
    <link>https://dev.to/maheshch</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%2F4072205%2F4677adad-705a-434f-bb7e-da0261a3cc42.png</url>
      <title>DEV Community: Mahesh</title>
      <link>https://dev.to/maheshch</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/maheshch"/>
    <language>en</language>
    <item>
      <title>Why We Built MailPort: A Modern Streaming Email SDK for Node.js</title>
      <dc:creator>Mahesh</dc:creator>
      <pubDate>Tue, 11 Aug 2026 02:50:11 +0000</pubDate>
      <link>https://dev.to/maheshch/why-we-built-mailport-a-modern-streaming-email-sdk-for-nodejs-lll</link>
      <guid>https://dev.to/maheshch/why-we-built-mailport-a-modern-streaming-email-sdk-for-nodejs-lll</guid>
      <description>&lt;h1&gt;
  
  
  How I Streamed a 100 MB Email Attachment in Node.js Without Buffering the Complete File
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Target Publication&lt;/strong&gt;: Dev.to / Hashnode / Medium&lt;br&gt;
&lt;strong&gt;Tags&lt;/strong&gt;: &lt;code&gt;#nodejs #typescript #webdev #performance #email&lt;/code&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  The Problem with Naive Email Attachment Buffering
&lt;/h2&gt;

&lt;p&gt;In standard Node.js email implementations, sending a multi-megabyte email attachment often loads the entire binary file into a Node.js &lt;code&gt;Buffer&lt;/code&gt; in memory.&lt;/p&gt;

&lt;p&gt;When encoding a 100 MB attachment to Base64:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The 100 MB raw buffer is loaded into heap memory.&lt;/li&gt;
&lt;li&gt;Base64 encoding creates a ~133 MB string.&lt;/li&gt;
&lt;li&gt;MIME line wrapping creates another string object.&lt;/li&gt;
&lt;li&gt;Total transient memory footprint exceeds 300+ MB for a single attachment!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If multiple concurrent requests stream large attachments, Node.js applications frequently experience V8 heap inflation, garbage collection pauses, or Out-Of-Memory (OOM) crashes.&lt;/p&gt;


&lt;h2&gt;
  
  
  The AsyncIterable Streaming Solution
&lt;/h2&gt;

&lt;p&gt;To eliminate buffer inflation, MailPort's MIME engine (&lt;code&gt;@mailport/mime&lt;/code&gt;) processes attachment data incrementally using &lt;code&gt;AsyncIterable&amp;lt;Uint8Array&amp;gt;&lt;/code&gt; streams.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Base64 Chunk Boundary Handling
&lt;/h3&gt;

&lt;p&gt;Base64 encoding transforms groups of 3 binary bytes into 4 ASCII characters. When streaming arbitrary file chunks (e.g. 64 KB or 10 MB chunks), a chunk boundary may split across a 3-byte tuple.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Base64StreamEncoder&lt;/code&gt; buffers only the leftover 1 or 2 bytes across chunk boundaries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Base64StreamEncoder&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;remainder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Uint8Array&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;Uint8Array&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="nf"&gt;encodeChunk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Uint8Array&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Combine 1-2 remainder bytes with incoming chunk&lt;/span&gt;
    &lt;span class="c1"&gt;// Process in multiples of 3 bytes&lt;/span&gt;
    &lt;span class="c1"&gt;// Preserve new remainder for next chunk&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;h3&gt;
  
  
  2. Direct Socket Pipeline
&lt;/h3&gt;

&lt;p&gt;The generated &lt;code&gt;AsyncIterable&amp;lt;Uint8Array&amp;gt;&lt;/code&gt; stream feeds directly into the TCP/TLS socket write queue with backpressure handling (&lt;code&gt;socket.write()&lt;/code&gt; + &lt;code&gt;drain&lt;/code&gt; event listener).&lt;/p&gt;




&lt;h2&gt;
  
  
  Empirical Benchmark Results
&lt;/h2&gt;

&lt;p&gt;We benchmarked streaming a 100 MB attachment on Node.js v24 (macOS ARM64):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Emitted Transmitted Payload&lt;/td&gt;
&lt;td&gt;136.84 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Throughput&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;387.57 MB/s&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Duration&lt;/td&gt;
&lt;td&gt;353 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Peak Heap Memory Delta&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;8.98 MB&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Peak heap memory usage remained under 9 MB while processing a 136 MB emitted payload!&lt;/p&gt;




&lt;h2&gt;
  
  
  Code Example
&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createReadStream&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:fs&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;createMailer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;smtp&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;mailport&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;mailer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createMailer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;smtp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;host&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;SMTP_HOST&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;587&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;user&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;SMTP_USER&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;pass&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;SMTP_PASSWORD&lt;/span&gt;&lt;span class="o"&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;mailer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;exports@example.com&lt;/span&gt;&lt;span class="dl"&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Monthly Data Backup&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;attachments&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="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;stream&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;backup.sql.gz&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;createReadStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./backup.sql.gz&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="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check out the MailPort repository on GitHub: &lt;a href="https://github.com/mahe-gi/mailport" rel="noopener noreferrer"&gt;https://github.com/mahe-gi/mailport&lt;/a&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>typescript</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
