DEV Community

Nikola Mitrovic
Nikola Mitrovic

Posted on

Automating Supplier Order Emails: Stop Copy-Pasting from Your Inbox

The Problem

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.

After building this automation three times across different companies, here's the approach that actually works in production.

Architecture Overview

You need three components:

  • Email receiver — captures inbound messages (IMAP polling or webhook)
  • Parser — extracts structured data from email body/attachments
  • Integrator — pushes parsed data to your database or ERP

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.

The Node.js Implementation

Here's a minimal example using imap-simple and some regex parsing. This listens for new emails, extracts order numbers and totals, then logs them:

const imaps = require('imap-simple');
const { simpleParser } = require('mailparser');

const config = {
  imap: {
    user: process.env.EMAIL_USER,
    password: process.env.EMAIL_PASSWORD,
    host: 'imap.gmail.com',
    port: 993,
    tls: true,
    tlsOptions: { rejectUnauthorized: false }
  }
};

async function processOrders() {
  const connection = await imaps.connect(config);
  await connection.openBox('INBOX');

  const searchCriteria = ['UNSEEN', ['FROM', 'orders@supplier.com']];
  const fetchOptions = { bodies: [''], markSeen: true };

  const messages = await connection.search(searchCriteria, fetchOptions);

  for (const item of messages) {
    const all = item.parts.find(part => part.which === '');
    const parsed = await simpleParser(all.body);

    // Extract order details (customize per supplier)
    const orderMatch = parsed.text.match(/Order #(\d+)/);
    const totalMatch = parsed.text.match(/Total: \$([\d,]+\.\d{2})/);

    if (orderMatch && totalMatch) {
      const order = {
        orderNumber: orderMatch[1],
        total: parseFloat(totalMatch[1].replace(',', '')),
        receivedAt: new Date()
      };

      console.log('Parsed order:', order);
      // await saveToDatabase(order);
    }
  }

  connection.end();
}

processOrders().catch(console.error);
Enter fullscreen mode Exit fullscreen mode

What This Doesn't Handle

This snippet works for demos, but production needs:

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

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.

The Real Cost

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.

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.

Try ParseForce

If you'd rather skip the plumbing entirely, check out ParseForce — 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.

Top comments (0)