<?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: Nikola Mitrovic</title>
    <description>The latest articles on Forem by Nikola Mitrovic (@nikola_mitrovic_922e2665f).</description>
    <link>https://forem.com/nikola_mitrovic_922e2665f</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%2F3395259%2Fe08340c0-33f8-4378-bf06-27110a0e1553.png</url>
      <title>Forem: Nikola Mitrovic</title>
      <link>https://forem.com/nikola_mitrovic_922e2665f</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/nikola_mitrovic_922e2665f"/>
    <language>en</language>
    <item>
      <title>How I turned an Android phone into an SMS API</title>
      <dc:creator>Nikola Mitrovic</dc:creator>
      <pubDate>Sat, 14 Mar 2026 09:03:22 +0000</pubDate>
      <link>https://forem.com/nikola_mitrovic_922e2665f/how-i-turned-an-android-phone-into-an-sms-api-38kc</link>
      <guid>https://forem.com/nikola_mitrovic_922e2665f/how-i-turned-an-android-phone-into-an-sms-api-38kc</guid>
      <description>&lt;p&gt;The story of SimGate (&lt;a href="https://simgate.app" rel="noopener noreferrer"&gt;https://simgate.app&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;SMS is still one of the most reliable ways to send notifications,&lt;br&gt;
alerts, and verification codes.&lt;/p&gt;

&lt;p&gt;But if you've ever looked at services like Twilio, you know the costs&lt;br&gt;
can add up quickly --- especially for small projects, internal tools, or&lt;br&gt;
experiments.&lt;/p&gt;

&lt;p&gt;So I started wondering:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What if a regular Android phone could act as an SMS gateway?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Turns out... it can.&lt;/p&gt;

&lt;p&gt;Recently I built a small system that turns an Android phone into a&lt;br&gt;
programmable SMS API.&lt;/p&gt;


&lt;h2&gt;
  
  
  The idea
&lt;/h2&gt;

&lt;p&gt;Every Android phone already has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  a SIM card&lt;/li&gt;
&lt;li&gt;  an SMS modem&lt;/li&gt;
&lt;li&gt;  an internet connection&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So instead of paying for SMS infrastructure, the phone itself can send&lt;br&gt;
messages.&lt;/p&gt;

&lt;p&gt;The missing piece is just connecting that phone to a backend.&lt;/p&gt;

&lt;p&gt;The architecture looks like this:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Your App
   │
   ▼
REST API
   │
   ▼
WebSocket connection
   │
   ▼
Android phone
   │
   ▼
Carrier SMS network
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Your backend sends a request → the phone receives it → the phone sends&lt;br&gt;
the SMS.&lt;/p&gt;


&lt;h2&gt;
  
  
  The architecture
&lt;/h2&gt;

&lt;p&gt;The system has three main parts.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Backend API
&lt;/h3&gt;

&lt;p&gt;The backend exposes a simple endpoint:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /send-sms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Example request:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"to"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"+381601234567"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello from API"&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 backend does not send SMS directly. Instead it forwards the message&lt;br&gt;
to a connected device over WebSocket.&lt;/p&gt;


&lt;h3&gt;
  
  
  2. Persistent device connection
&lt;/h3&gt;

&lt;p&gt;When the Android app starts, it opens a WebSocket connection to the&lt;br&gt;
backend.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;connectDevice&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;deviceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;abc123&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the backend knows that this specific phone is online.&lt;/p&gt;

&lt;p&gt;Whenever a new SMS request arrives, the backend pushes the message to&lt;br&gt;
that device.&lt;/p&gt;


&lt;h3&gt;
  
  
  3. Android SMS sender
&lt;/h3&gt;

&lt;p&gt;The Android app receives the message and sends it using the native SMS&lt;br&gt;
manager.&lt;/p&gt;

&lt;p&gt;On Android this is surprisingly simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;SmsManager&lt;/span&gt; &lt;span class="n"&gt;smsManager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SmsManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDefault&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;smsManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sendTextMessage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;phoneNumber&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it.&lt;/p&gt;

&lt;p&gt;The phone sends the SMS through the carrier network just like any normal&lt;br&gt;
message.&lt;/p&gt;


&lt;h2&gt;
  
  
  Why this is interesting
&lt;/h2&gt;

&lt;p&gt;This approach has some interesting advantages.&lt;/p&gt;
&lt;h3&gt;
  
  
  No SMS provider required
&lt;/h3&gt;

&lt;p&gt;You don't need Twilio, Nexmo, or other gateways.&lt;/p&gt;

&lt;p&gt;The SIM card in the phone handles everything.&lt;/p&gt;


&lt;h3&gt;
  
  
  Extremely cheap
&lt;/h3&gt;

&lt;p&gt;If you already have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  a spare Android phone&lt;/li&gt;
&lt;li&gt;  a SIM card with SMS included&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then your cost is basically zero.&lt;/p&gt;


&lt;h3&gt;
  
  
  Useful for internal tools
&lt;/h3&gt;

&lt;p&gt;This setup works well for things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  server alerts&lt;/li&gt;
&lt;li&gt;  IoT notifications&lt;/li&gt;
&lt;li&gt;  internal automation&lt;/li&gt;
&lt;li&gt;  dev experiments&lt;/li&gt;
&lt;li&gt;  sending messages in regions where SMS APIs are limited&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Challenges I ran into
&lt;/h2&gt;

&lt;p&gt;This was not completely trivial.&lt;/p&gt;

&lt;p&gt;Some problems that needed solving:&lt;/p&gt;
&lt;h3&gt;
  
  
  Persistent connectivity
&lt;/h3&gt;

&lt;p&gt;Phones disconnect from networks frequently.&lt;/p&gt;

&lt;p&gt;Keeping a reliable WebSocket connection required retry logic and&lt;br&gt;
heartbeat checks.&lt;/p&gt;


&lt;h3&gt;
  
  
  Device registration
&lt;/h3&gt;

&lt;p&gt;Each phone needs a unique identity so the backend knows where to route&lt;br&gt;
SMS messages.&lt;/p&gt;

&lt;p&gt;I solved this by generating a device ID during registration and pairing&lt;br&gt;
it with the API key.&lt;/p&gt;


&lt;h3&gt;
  
  
  Background restrictions
&lt;/h3&gt;

&lt;p&gt;Android can aggressively kill background processes.&lt;/p&gt;

&lt;p&gt;The app needs to run as a foreground service to stay alive reliably.&lt;/p&gt;


&lt;h2&gt;
  
  
  Example workflow
&lt;/h2&gt;

&lt;p&gt;Once everything is connected, sending SMS looks like this.&lt;/p&gt;

&lt;p&gt;Example request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://api.example.com/send-sms   &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer API_KEY"&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="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
        "to": "+381601234567",
        "message": "Server is back online"
      }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The connected phone immediately sends the SMS.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I built this
&lt;/h2&gt;

&lt;p&gt;Originally this started as an experiment to see if it was possible to&lt;br&gt;
build a simple SMS gateway using commodity hardware.&lt;/p&gt;

&lt;p&gt;After getting it working, I turned it into a small service called&lt;br&gt;
SimGate that lets you connect a phone and send SMS through an API.&lt;/p&gt;

&lt;p&gt;The idea is simple:&lt;/p&gt;

&lt;p&gt;Phone + SIM → SMS API&lt;/p&gt;

&lt;p&gt;If you're curious or want to try it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://simgate.app" rel="noopener noreferrer"&gt;https://simgate.app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'd also love to hear how other people handle SMS in small projects or&lt;br&gt;
internal tooling.&lt;/p&gt;

&lt;p&gt;Are you using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Twilio&lt;/li&gt;
&lt;li&gt;  self-hosted GSM modems&lt;/li&gt;
&lt;li&gt;  Android devices&lt;/li&gt;
&lt;li&gt;  something else entirely?&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>sms</category>
      <category>api</category>
      <category>smsapi</category>
    </item>
    <item>
      <title>Automating Supplier Order Emails: Stop Copy-Pasting from Your Inbox</title>
      <dc:creator>Nikola Mitrovic</dc:creator>
      <pubDate>Fri, 06 Mar 2026 10:05:46 +0000</pubDate>
      <link>https://forem.com/nikola_mitrovic_922e2665f/automating-supplier-order-emails-stop-copy-pasting-from-your-inbox-25fn</link>
      <guid>https://forem.com/nikola_mitrovic_922e2665f/automating-supplier-order-emails-stop-copy-pasting-from-your-inbox-25fn</guid>
      <description>&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Most B2B operations still run on email. Your suppliers send order confirmations, shipping notices, and invoices to a shared inbox, and someone on your team manually copies data into your system. It's tedious, error-prone, and doesn't scale.&lt;/p&gt;

&lt;p&gt;After building this automation three times across different companies, here's the approach that actually works in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture Overview
&lt;/h2&gt;

&lt;p&gt;You need three components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Email receiver&lt;/strong&gt; — captures inbound messages (IMAP polling or webhook)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parser&lt;/strong&gt; — extracts structured data from email body/attachments&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integrator&lt;/strong&gt; — pushes parsed data to your database or ERP&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The tricky part isn't any single piece—it's handling the chaos of real-world supplier emails. One vendor sends PDFs, another uses plain text with inconsistent formatting, and a third embeds everything in HTML tables.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Node.js Implementation
&lt;/h2&gt;

&lt;p&gt;Here's a minimal example using &lt;code&gt;imap-simple&lt;/code&gt; and some regex parsing. This listens for new emails, extracts order numbers and totals, then logs them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;imaps&lt;/span&gt; &lt;span class="o"&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;imap-simple&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;simpleParser&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&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;mailparser&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="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;imap&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;EMAIL_USER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;password&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_PASSWORD&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;imap.gmail.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;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;993&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;tls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;tlsOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;rejectUnauthorized&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;processOrders&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;connection&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;imaps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;openBox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INBOX&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;searchCriteria&lt;/span&gt; &lt;span class="o"&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;UNSEEN&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;FROM&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;orders@supplier.com&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;fetchOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;bodies&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="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;markSeen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchCriteria&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fetchOptions&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;item&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;all&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;part&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;part&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;which&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parsed&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;simpleParser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Extract order details (customize per supplier)&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;orderMatch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&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;/Order #&lt;/span&gt;&lt;span class="se"&gt;(\d&lt;/span&gt;&lt;span class="sr"&gt;+&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;totalMatch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&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;/Total: &lt;/span&gt;&lt;span class="se"&gt;\$([\d&lt;/span&gt;&lt;span class="sr"&gt;,&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;\.\d{2})&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;orderMatch&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;totalMatch&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;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;orderNumber&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;orderMatch&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;parseFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;totalMatch&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;,&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="p"&gt;)),&lt;/span&gt;
        &lt;span class="na"&gt;receivedAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;

      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Parsed order:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="c1"&gt;// await saveToDatabase(order);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;processOrders&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What This Doesn't Handle
&lt;/h2&gt;

&lt;p&gt;This snippet works for demos, but production needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Multi-vendor parsing logic&lt;/strong&gt; — each supplier has different formats&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PDF extraction&lt;/strong&gt; — many orders come as attachments&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retry logic&lt;/strong&gt; — emails sometimes arrive out of order or get corrupted&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Schema validation&lt;/strong&gt; — ensuring extracted data matches your database constraints&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring&lt;/strong&gt; — you need alerts when parsing fails&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Building all of this from scratch takes weeks. You'll write custom parsers for each supplier, handle authentication edge cases, and spend weekends debugging why one vendor's emails suddenly changed format.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Cost
&lt;/h2&gt;

&lt;p&gt;Maintenance is the killer. Suppliers change their email templates without warning. Your regex breaks. Someone has to debug it at 9 PM because orders aren't flowing through.&lt;/p&gt;

&lt;p&gt;The automation saves time compared to manual entry, but only if you account for the ongoing maintenance burden. If you're processing fewer than 50 orders per day, honestly, the manual approach might cost less in total engineering time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try ParseForce
&lt;/h2&gt;

&lt;p&gt;If you'd rather skip the plumbing entirely, check out &lt;a href="https://parseforce.io/" rel="noopener noreferrer"&gt;ParseForce&lt;/a&gt; — it handles inbound email parsing, schema validation, and webhook delivery out of the box. The architecture is solid for teams that want to focus on business logic instead of email infrastructure.&lt;/p&gt;

</description>
      <category>node</category>
      <category>automation</category>
      <category>webdev</category>
      <category>ai</category>
    </item>
    <item>
      <title>Parsing Incoming Emails into Structured JSON with Node and AI</title>
      <dc:creator>Nikola Mitrovic</dc:creator>
      <pubDate>Tue, 03 Mar 2026 10:48:21 +0000</pubDate>
      <link>https://forem.com/nikola_mitrovic_922e2665f/parsing-incoming-emails-into-structured-json-with-node-and-ai-2979</link>
      <guid>https://forem.com/nikola_mitrovic_922e2665f/parsing-incoming-emails-into-structured-json-with-node-and-ai-2979</guid>
      <description>&lt;p&gt;Email is still one of the most common “integration APIs” in business and that's why I made &lt;a href="https://www.parseforce.io" rel="noopener noreferrer"&gt;https://www.parseforce.io&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Invoices. Shipping notices. Order confirmations. Supplier updates.&lt;/p&gt;

&lt;p&gt;And in many cases… email is the &lt;em&gt;only&lt;/em&gt; integration point you get.&lt;/p&gt;

&lt;p&gt;The problem?&lt;/p&gt;

&lt;p&gt;Emails are messy.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Layout changes&lt;/li&gt;
&lt;li&gt;Forwarded threads&lt;/li&gt;
&lt;li&gt;HTML formatting&lt;/li&gt;
&lt;li&gt;Different senders, different structures&lt;/li&gt;
&lt;li&gt;Slight wording tweaks that break everything&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Yet inside those emails is structured data you actually need.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Regex Trap
&lt;/h2&gt;

&lt;p&gt;Most teams start with regex or template-based parsing.&lt;/p&gt;

&lt;p&gt;It works at first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const match = emailBody.match(/Total:\s*\$([0-9,\.]+)/);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then one day:&lt;/p&gt;

&lt;p&gt;“Total” becomes “Amount Due”&lt;/p&gt;

&lt;p&gt;The currency moves&lt;/p&gt;

&lt;p&gt;The supplier updates their template&lt;/p&gt;

&lt;p&gt;Someone forwards the email&lt;/p&gt;

&lt;p&gt;And your parser breaks.&lt;/p&gt;

&lt;p&gt;You’re now maintaining parsing logic instead of building product.&lt;/p&gt;

&lt;p&gt;A Different Approach&lt;/p&gt;

&lt;p&gt;Instead of matching patterns, define the schema you want:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "invoiceNumber": "string",
  "items": [],
  "total": "number",
  "currency": "string"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then extract structured JSON that conforms to that schema.&lt;/p&gt;

&lt;p&gt;Your workflow becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Incoming email
↓
Extract structured data
↓
Validate
↓
Send to webhook
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now your backend only deals with clean JSON.&lt;/p&gt;

&lt;p&gt;Making Email Feel Like Webhooks&lt;/p&gt;

&lt;p&gt;The goal is simple:&lt;/p&gt;

&lt;p&gt;Turn this:&lt;/p&gt;

&lt;p&gt;email → chaos&lt;/p&gt;

&lt;p&gt;Into this:&lt;/p&gt;

&lt;p&gt;email → structured JSON → webhook&lt;/p&gt;

&lt;p&gt;So your systems can treat email like any other API input.&lt;/p&gt;

&lt;p&gt;A Practical Note&lt;/p&gt;

&lt;p&gt;If you go this route:&lt;/p&gt;

&lt;p&gt;Always store raw emails&lt;/p&gt;

&lt;p&gt;Validate extracted fields&lt;/p&gt;

&lt;p&gt;Handle low-confidence cases&lt;/p&gt;

&lt;p&gt;Expect edge cases&lt;/p&gt;

&lt;p&gt;Email isn’t going away.&lt;br&gt;
But it doesn’t have to be painful.&lt;br&gt;
More details about the &lt;a href="https://www.parseforce.io" rel="noopener noreferrer"&gt;tool&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>javascript</category>
      <category>programming</category>
    </item>
    <item>
      <title>I tried parsing emails with regex. It went exactly how you think.</title>
      <dc:creator>Nikola Mitrovic</dc:creator>
      <pubDate>Mon, 02 Mar 2026 15:24:14 +0000</pubDate>
      <link>https://forem.com/nikola_mitrovic_922e2665f/i-tried-parsing-emails-with-regex-it-went-exactly-how-you-think-2j9c</link>
      <guid>https://forem.com/nikola_mitrovic_922e2665f/i-tried-parsing-emails-with-regex-it-went-exactly-how-you-think-2j9c</guid>
      <description>&lt;p&gt;Recently I needed to &lt;strong&gt;process incoming emails automatically&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The idea sounded simple:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Email arrives → extract some fields → trigger a webhook&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;order confirmations
&lt;/li&gt;
&lt;li&gt;invoice emails
&lt;/li&gt;
&lt;li&gt;shipping notifications
&lt;/li&gt;
&lt;li&gt;support messages
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nothing complicated.&lt;/p&gt;

&lt;p&gt;Or so I thought.&lt;/p&gt;




&lt;h2&gt;
  
  
  Attempt #1 — Regex
&lt;/h2&gt;

&lt;p&gt;Like most developers, I started with regex.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const price = email.match(/Total:\s\$(\d+)/)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;For the first email it worked perfectly.&lt;/p&gt;

&lt;p&gt;Then the next email came in and said:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Amount paid: $29
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then another one said:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Total price: USD 29
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then an HTML email arrived with nested tables, inline styles, and formatting from what looked like &lt;strong&gt;2004 Outlook templates&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;At this point my regex slowly evolved into something like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/(Total|Amount|Price).*?(\$|USD)?\s?(\d+(\.\d+)?)/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Which is usually the moment you realize the approach is already doomed.&lt;/p&gt;




&lt;h2&gt;
  
  
  Attempt #2 — Parsing the HTML
&lt;/h2&gt;

&lt;p&gt;Okay fine.&lt;/p&gt;

&lt;p&gt;Let's parse the HTML instead.&lt;/p&gt;

&lt;p&gt;That led to code like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const dom = new JSDOM(emailHtml)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Which &lt;em&gt;sometimes&lt;/em&gt; worked.&lt;/p&gt;

&lt;p&gt;Except email HTML is a special kind of chaos.&lt;/p&gt;

&lt;p&gt;You get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;tables inside tables
&lt;/li&gt;
&lt;li&gt;inline styles everywhere
&lt;/li&gt;
&lt;li&gt;different layouts for every sender
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And suddenly you're maintaining &lt;strong&gt;custom parsers for every email format&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The real problem
&lt;/h2&gt;

&lt;p&gt;Emails aren't structured data.&lt;/p&gt;

&lt;p&gt;They're &lt;strong&gt;written for humans&lt;/strong&gt;, not machines.&lt;/p&gt;

&lt;p&gt;And every sender formats them differently.&lt;/p&gt;

&lt;p&gt;Trying to enforce rigid parsing rules becomes fragile very quickly.&lt;/p&gt;




&lt;h2&gt;
  
  
  The obvious solution (in hindsight)
&lt;/h2&gt;

&lt;p&gt;Instead of trying to force strict parsing rules…&lt;/p&gt;

&lt;p&gt;Why not let &lt;strong&gt;AI interpret the email&lt;/strong&gt; and extract the fields you want?&lt;/p&gt;

&lt;p&gt;Example email:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Subject: Order confirmation
Customer: John Smith
Product: T-shirt
Total: $39
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Structured output:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "customer": "John Smith",
  "product": "T-shirt",
  "total": 39
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now your backend receives &lt;strong&gt;clean structured data&lt;/strong&gt; instead of raw email text.&lt;/p&gt;




&lt;h2&gt;
  
  
  So I built a small tool
&lt;/h2&gt;

&lt;p&gt;Mostly because I kept running into this problem again and again.&lt;/p&gt;

&lt;p&gt;It's called &lt;strong&gt;ParseForce&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The flow is simple:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Incoming email → AI parsing → structured JSON → webhook
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get a &lt;strong&gt;unique inbox&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Send emails to it&lt;/li&gt;
&lt;li&gt;Define the schema you want&lt;/li&gt;
&lt;li&gt;Receive &lt;strong&gt;structured JSON in your webhook&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Some things it works well for
&lt;/h2&gt;

&lt;p&gt;So far I've been using it for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;parsing &lt;strong&gt;order confirmation emails&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;extracting &lt;strong&gt;invoice data&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;processing &lt;strong&gt;lead emails&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;triggering &lt;strong&gt;automation workflows&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Basically anything where an email contains &lt;strong&gt;data you want your system to understand&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  If you're curious
&lt;/h2&gt;

&lt;p&gt;You can check it out here:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://parseforce.io" rel="noopener noreferrer"&gt;https://parseforce.io&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm also curious how others deal with this problem.&lt;/p&gt;

&lt;p&gt;Are you using regex, templates, or something else entirely?&lt;/p&gt;




&lt;h1&gt;
  
  
  node #webdev #saas #automation #ai
&lt;/h1&gt;

</description>
    </item>
    <item>
      <title>How I’m Building an AI Try-On Tool for Clothing Brands (Behind the Scenes)</title>
      <dc:creator>Nikola Mitrovic</dc:creator>
      <pubDate>Wed, 10 Dec 2025 20:03:32 +0000</pubDate>
      <link>https://forem.com/nikola_mitrovic_922e2665f/how-im-building-an-ai-try-on-tool-for-clothing-brands-behind-the-scenes-3pmc</link>
      <guid>https://forem.com/nikola_mitrovic_922e2665f/how-im-building-an-ai-try-on-tool-for-clothing-brands-behind-the-scenes-3pmc</guid>
      <description>&lt;p&gt;Over the past few months, I’ve been working closely with a few small clothing brands, and one problem kept coming up in every conversation:&lt;/p&gt;

&lt;p&gt;“We can get new inventory fast… but product photos slow everything down.”&lt;/p&gt;

&lt;p&gt;That fascinated me. Most boutiques spend:&lt;br&gt;
days coordinating photoshoots&lt;br&gt;
money on models + photographers&lt;br&gt;
time editing everything&lt;br&gt;
and meanwhile, new items sit in inventory waiting for photos&lt;br&gt;
One boutique owner told me:&lt;br&gt;
“I can add products to Shopify the same day I get them, but photos take 2–3 weeks. I lose sales every time.”&lt;br&gt;
That sentence is basically what kicked off this whole project.&lt;/p&gt;

&lt;p&gt;🧪 Early experiments&lt;br&gt;
I started by playing with background removal tools, virtual studios, early AI generation models, pose-transfer models&lt;br&gt;
Results were… okay-ish. Cool tech, but nothing you’d confidently publish on a real store.&lt;/p&gt;

&lt;p&gt;What I really wanted was something like:&lt;br&gt;
Upload garment → get realistic model photo → done&lt;br&gt;
No photoshoot, no scheduling, no waiting.&lt;/p&gt;

&lt;p&gt;⚙️ The tech stack I’m using&lt;br&gt;
Right now the project is built with:&lt;br&gt;
Next.js (frontend)&lt;br&gt;
Supabase (auth + storage)&lt;br&gt;
Fal.ai (AI inference endpoints)&lt;br&gt;
Vercel (hosting)&lt;/p&gt;

&lt;p&gt;The flow looks like this: User uploads a garment image -&amp;gt; It runs through preprocessing (crop, contour detection, smoothing) -&amp;gt; Sent to an AI model for realistic try-on -&amp;gt; Post-processing improves lighting + consistency -&amp;gt; delivered as a final product photo&lt;/p&gt;

&lt;p&gt;Still improving it — realism is the hardest part but now it's more realistic than others that I played with.&lt;/p&gt;

&lt;p&gt;🎯 The goal&lt;br&gt;
I’m trying to answer one simple question:&lt;br&gt;
“Can small clothing brands get store-ready model photos without photoshoots?”&lt;br&gt;
I’m not sure yet, but early tests have been promising enough to keep building.&lt;br&gt;
Some brands loved it:&lt;br&gt;
“This saves me days.”&lt;br&gt;
Some weren’t ready:&lt;br&gt;
“I still prefer real models.”&lt;br&gt;
Understanding that gap is part of this whole journey.&lt;/p&gt;

&lt;p&gt;🚀 Launching soon on Product Hunt&lt;br&gt;
I’m planning to launch the project on Product Hunt soon (next week).&lt;br&gt;
If you like AI + e-commerce + build-in-public stuff, I’ll share the link when it goes live.&lt;br&gt;
Would love any thoughts, feedback, or questions — especially from developers working with:&lt;br&gt;
generative models&lt;br&gt;
computer vision&lt;br&gt;
e-commerce automation&lt;br&gt;
apparel tech&lt;br&gt;
Happy to nerd out on the technical side if anyone’s interested.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.fitsnapai.app" rel="noopener noreferrer"&gt;https://www.fitsnapai.app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Results:&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2F1xg1n0tof0o5cnvdoeqm.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.amazonaws.com%2Fuploads%2Farticles%2F1xg1n0tof0o5cnvdoeqm.png" alt=" " width="800" height="664"&gt;&lt;/a&gt;&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Ftfde1lsvsoqru3lrrsb7.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2Ftfde1lsvsoqru3lrrsb7.jpg" alt=" " width="576" height="1024"&gt;&lt;/a&gt;&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2Fklpxizdts46363fz8b7d.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2Fklpxizdts46363fz8b7d.jpg" alt=" " width="800" height="655"&gt;&lt;/a&gt;&lt;/p&gt;

&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.amazonaws.com%2Fuploads%2Farticles%2F2d9bm3v3hrqj6jieqneo.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2F2d9bm3v3hrqj6jieqneo.jpg" alt=" " width="768" height="1376"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>nanobanana</category>
      <category>saas</category>
    </item>
    <item>
      <title>Interested in SMS over API using your own SIM card?</title>
      <dc:creator>Nikola Mitrovic</dc:creator>
      <pubDate>Sat, 13 Sep 2025 15:06:32 +0000</pubDate>
      <link>https://forem.com/nikola_mitrovic_922e2665f/-2n5a</link>
      <guid>https://forem.com/nikola_mitrovic_922e2665f/-2n5a</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/nikola_mitrovic_922e2665f" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3395259%2Fe08340c0-33f8-4378-bf06-27110a0e1553.png" alt="nikola_mitrovic_922e2665f"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/nikola_mitrovic_922e2665f/how-i-send-sms-from-my-react-app-using-my-own-phone-and-sim-card-4n0p" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;How I Send SMS From My React App Using My Own Phone and SIM Card&lt;/h2&gt;
      &lt;h3&gt;Nikola Mitrovic ・ Sep 13 '25&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#react&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#sms&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#api&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>react</category>
      <category>webdev</category>
      <category>sms</category>
      <category>api</category>
    </item>
    <item>
      <title>How I Send SMS From My React App Using My Own Phone and SIM Card</title>
      <dc:creator>Nikola Mitrovic</dc:creator>
      <pubDate>Sat, 13 Sep 2025 13:07:48 +0000</pubDate>
      <link>https://forem.com/nikola_mitrovic_922e2665f/how-i-send-sms-from-my-react-app-using-my-own-phone-and-sim-card-4n0p</link>
      <guid>https://forem.com/nikola_mitrovic_922e2665f/how-i-send-sms-from-my-react-app-using-my-own-phone-and-sim-card-4n0p</guid>
      <description>&lt;p&gt;Most tutorials on “sending SMS from your app” point you to services like Twilio, where you pay per message. That’s fine for small projects, but once you start sending a lot of texts, those charges add up quickly.&lt;/p&gt;

&lt;p&gt;I wanted something different: a way to send SMS without paying a third-party provider — just using my own Android phone and SIM card. That’s why I built &lt;a href="https://www.simgate.app" rel="noopener noreferrer"&gt;SimGate&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this post I’ll show you how I wired up my phone to send an SMS directly from a simple React app with just one API call.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The idea&lt;br&gt;
Install an app on your Android phone.&lt;br&gt;
The app connects to &lt;a href="https://www.simgate.app" rel="noopener noreferrer"&gt;SimGate&lt;/a&gt; and exposes an API endpoint.&lt;br&gt;
Your frontend or backend makes a POST request with the phone number + message.&lt;br&gt;
Your phone’s SIM card sends the SMS.&lt;br&gt;
No middleman. No per-SMS fee. Just your device and your mobile plan.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Setting up the phone&lt;br&gt;
Install the SimGate Android app.&lt;br&gt;
Log in and register the device.&lt;br&gt;
The app generates an API key you’ll use in your code.&lt;br&gt;
That’s it — your phone is now ready to act as a mini SMS gateway.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;3.Sending an SMS:&lt;/p&gt;

&lt;p&gt;Here’s the simplest possible curl example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -X POST https://api.simgate.app/v1/sms/send \
  -H "Content-Type: application/json" \
  -H "x-api-key: &amp;lt;YOUR_API_KEY&amp;gt;" \
  -d '{
    "deviceId": "&amp;lt;YOUR_DEVICE_ID&amp;gt;",
    "to": "+15551234567",
    "message": "SMS from curl"
  }'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sending it from react is quite simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async function sendSms() {
  const res = await fetch("https://api.simgate.app/v1/sms/send", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "x-api-key": "&amp;lt;YOUR_API_KEY&amp;gt;",
    },
    body: JSON.stringify({
      deviceId: "&amp;lt;YOUR_DEVICE_ID&amp;gt;",
      to: "+15551234567",
      message: "Hello from my React app",
    }),
  });

  const data = await res.json();
  console.log("SMS response:", data);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As long as your phone has connection SMS is shipped!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.simgate.app" rel="noopener noreferrer"&gt;https://www.simgate.app&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>sms</category>
      <category>api</category>
    </item>
    <item>
      <title>Why I’m building SimGate: An SMS API without per-message fees</title>
      <dc:creator>Nikola Mitrovic</dc:creator>
      <pubDate>Mon, 28 Jul 2025 20:46:36 +0000</pubDate>
      <link>https://forem.com/nikola_mitrovic_922e2665f/why-im-building-simgate-an-sms-api-without-per-message-fees-16mm</link>
      <guid>https://forem.com/nikola_mitrovic_922e2665f/why-im-building-simgate-an-sms-api-without-per-message-fees-16mm</guid>
      <description>&lt;p&gt;I’m a full-stack developer who’s always looking for simple, affordable tools, especially when building for side projects or indie SaaS ideas.&lt;/p&gt;

&lt;p&gt;Recently, I ran into a familiar problem:&lt;br&gt;
Sending SMS through APIs like Twilio gets expensive fast.&lt;br&gt;
Even basic features like 2FA or delivery alerts can become unsustainable when you're paying per message, especially on low-margin or small-scale projects.&lt;/p&gt;

&lt;p&gt;That’s when I decided to build SimGate — a lightweight developer tool that lets you send SMS through your own Android phone and SIM card, using a clean API, without per-message fees.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who is SimGate for?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Indie devs building internal tools or MVPs&lt;/li&gt;
&lt;li&gt;Solo SaaS founders with &amp;lt;1k users&lt;/li&gt;
&lt;li&gt;Local delivery apps, clinics, or automations that need recurring SMS&lt;/li&gt;
&lt;li&gt;IoT/sensor projects that send alerts&lt;/li&gt;
&lt;li&gt;Anyone who’s tired of “$0.something per SMS” adding up over time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;How does it work?&lt;/strong&gt;&lt;br&gt;
SimGate connects to your phone via a mobile gateway app. Once paired, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Send SMS using a secure API&lt;/li&gt;
&lt;li&gt;Avoid cloud provider markups&lt;/li&gt;
&lt;li&gt;Pay a flat monthly subscription instead of per message (free plan will be available as well)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This way, your phone becomes your own private SMS gateway.&lt;br&gt;
I’m keeping the first version lean — just enough to get real use cases working.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Want to try it?&lt;/strong&gt;&lt;br&gt;
I’ve opened up a waitlist to gather early interest and invite a few testers as soon as the MVP is live.&lt;/p&gt;

&lt;p&gt;If this solves a problem for you — or just sounds interesting — you can join here:&lt;br&gt;
👉 &lt;a href="https://www.simgate.app" rel="noopener noreferrer"&gt;https://www.simgate.app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks for reading — and if you’ve ever struggled with SMS pricing or built your own DIY solution, I’d love to hear your story in the comments!&lt;/p&gt;

&lt;p&gt;Nik&lt;br&gt;
&lt;a href="mailto:dev@simgate.app"&gt;dev@simgate.app&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
