In the logistics industry, freight brokers act as middle-men between shippers (customers) who need cargo moved and carriers (trucking companies) who own the assets to transport it. Historically, this matching process is incredibly manual: a broker receives a free-text email from a customer, parses the shipment lanes, copies the details into multiple emails to carriers to solicit quotes, waits for bids, triggers a negotiation round, adds a margin, proposes a price back to the customer, and finally drafts a Bill of Lading (BOL).

To automate this high-friction email loop, I created Freight Agent AWS—an automated competitive freight bidding platform. Built using a serverless architecture on AWS Lambda, API Gateway, and Amazon S3, it orchestrates the entire bidding lifecycle using Cerebras LLM (Llama-3.1) for sub-second email intelligence, and PostgreSQL with pgvector to match historical shipping lane data.

In this post, we’ll walk through the system’s architecture, explain the bidding cycle, and break down the anatomy of the email connector that acts as the platform’s nervous system.


💡 The Problem: The Manual Email Bottleneck

Freight brokers are constantly flooded with unstructured inquiry emails containing shipping requests like:

“Need a quote for 4 pallets of class 70 auto parts from Detroit, MI to Laredo, TX for next Tuesday. Weight is 8,500 lbs, dock-to-dock, no hazmat.”

A typical broker must:

  1. Parse details manually (Origin, Destination, Weight, Class, Hazmat status).
  2. Benchmark the lane using historical spreadsheet rates to estimate standard costs.
  3. Email multiple carriers to request quotes.
  4. Manage bidding deadlines and follow up to get the best pricing.
  5. Trigger a Re-Bid round to let carriers lower their rates when margins are tight.
  6. Apply markups and propose the final quote to the customer.

By automating this sequence, brokers can handle 10x the volume, eliminate data-entry errors, and secure the lowest carrier costs in real-time.


🏗️ 1. Core Quote State & Bid Cycle Flow

The lifecycle of a quote is managed by a state machine that transitions across 10 stages: INTAKE -> OUT_TO_CARRIERS -> FIRST_ROUND_RECEIVED -> RE_BID_ROUND -> QUOTE_SENT -> AWAITING_APPROVAL -> APPROVED -> IN_TRANSIT -> COMPLETED -> LOST.

Here is how the automated workflow operates when an inquiry arrives:

flowchart TD
    Customer["Customer Email"] -->|inbound email| Mailbox["Mailpit / Gmail Inbox"]
    Mailbox -->|webhook / polling| Ingestion["Intake Service"]
    
    subgraph Backend ["FastAPI Application"]
        Ingestion -->|1. Parse Email| LLM["Cerebras LLM Service"]
        LLM -->|Extract parameters| DB[("PostgreSQL + pgvector")]
        
        DB -->|2. RAG Query| RAG["Embedding & Historical RAG"]
        RAG -->|Lane benchmark| Orchestrator["Workflow Orchestrator"]
        
        Orchestrator -->|3. Status OUT_TO_CARRIERS| Outbound["SMTP Service"]
        Outbound -->|RFQ Email| Carriers["Carriers Network"]
        
        Carriers -->|4. Submit Bids| BidIngestion["Bid Parser"]
        BidIngestion -->|Record Bids| DB
        
        Orchestrator -->|5. Status RE_BID_ROUND| Rebid["Best & Final Trigger"]
        Rebid -->|Cheapest rate notification| Outbound
        
        Orchestrator -->|6. Status QUOTE_SENT| Markup["Markup Engine"]
        Markup -->|Apply Customer rules| CustProposal["Customer Quote Compose"]
        CustProposal -->|Customer Proposal Email| Customer
        
        Customer -->|7. Approved| WorkflowApprove["Booking Logic"]
        Customer -->|7. Rejected| WorkflowReject["Loss Logger"]
        
        WorkflowApprove -->|Proceed Booking| Outbound
        WorkflowApprove -->|BOL generation| BOLService["BOL & PandaDoc Service"]
        BOLService -->|Draft PandaDoc invoice| DB
    end
    
    subgraph Frontend ["React Vite Client"]
        UI["Web Dashboard"] -->|Get pipeline stats / Trigger mock actions| Backend
        UI -->|Pipeline Kanban Board| Broker["Freight Broker"]
        UI -->|Analytics Center| Broker
        UI -->|Invoice Ledger| Broker
    end

Flow Highlights

  • Intake Parsing: A Python ingestion service watches the broker’s mailbox. When an email is fetched, Cerebras Llama-3.1-70B extracts key logistics attributes in sub-second inference speed.
  • Historical Lane RAG: The backend vectorizes the shipping lane (e.g. Detroit to Laredo) and queries the PostgreSQL database using pgvector similarity search (<=>) to fetch historical prices, helping the broker benchmark the bids.
  • Automated Carrier RFQs: The engine automatically emails a selected network of carriers with an RFQ. As carriers reply with pricing and transit times, the email system parses the values and inserts them into the DB.
  • Re-Bid Trigger: If a carrier submits a bid, the orchestrator triggers a time-bound “Re-Bid Round”, alerting other carriers of the current lowest price (without revealing identity) to drive down costs.
  • Approval & BOL Drafting: Once the bid window closes, the broker approves the best price on their React Kanban board. The system automatically creates a Bill of Lading (BOL), syncs details to the invoice ledger, and drafts booking confirmations.

☁️ 2. AWS Serverless Architecture

To make this application highly scalable, cost-efficient, and easy to maintain, it is built entirely using serverless components on AWS. The FastAPI backend is adapted to AWS Lambda via Mangum, and S3 is utilized for both static web hosting and attachment storage.

graph TD
    subgraph Client ["Client Tier"]
        Browser["React Frontend - Vite"]
    end

    subgraph AWS ["AWS Cloud Infrastructure"]
        subgraph StaticHosting ["S3 Web Hosting"]
            FrontendBucket["S3 Frontend Bucket - freight-agent-frontend-dev-*"]
        end

        subgraph APIGateway ["API Gateway"]
            HttpApi["HTTP API Gateway - proxy path"]
        end

        subgraph Compute ["Serverless Compute"]
            ApiLambda["FastAPI App Lambda - app.main.handler"]
            CronLambda["Cron Processor Lambda - app.main.cron_handler"]
        end

        subgraph EventBridge ["Scheduling"]
            CronRule["EventBridge Rule - rate 1 minute"]
        end

        subgraph Storage ["Storage and Database"]
            Postgres["Amazon RDS PostgreSQL - with pgvector"]
            PrivateS3["Private S3 Bucket - dispatch-private"]
        end
    end

    subgraph External ["External Services"]
        Cerebras["Cerebras AI API - Llama-3-70B/8B"]
        EmailServer["Mailpit / SMTP and IMAP Server"]
        GoogleAuth["Google OAuth 2.0"]
    end

    %% Interactions
    Browser -->|Fetches Static Assets| FrontendBucket
    Browser -->|API Requests| HttpApi
    HttpApi -->|Invokes| ApiLambda

    CronRule -->|Triggers Every Minute| CronLambda

    %% Lambda Operations
    ApiLambda -->|SQL Queries and pgvector RAG| Postgres
    ApiLambda -->|Read/Write Attachments| PrivateS3
    ApiLambda -->|Google SSO / Authentication| GoogleAuth

    CronLambda -->|Read/Write Bids and Quotes| Postgres
    CronLambda -->|Check Workflow Timers| Postgres
    CronLambda -->|Poll IMAP and Send SMTP| EmailServer
    CronLambda -->|LLM Parse and Extract Bids| Cerebras
    
    %% Shared DB access
    ApiLambda -.->|Internal Service Calls| Cerebras

AWS Infrastructure breakdown:

  • FastAPI API Lambda: Standard endpoints (e.g. quotes tracking, carrier listings, analytics summaries) are served via API Gateway routing HTTP traffic directly into a FastAPI Lambda function.
  • Cron Processor Lambda: A decoupled cron Lambda is invoked every minute by Amazon EventBridge to poll the IMAP mail server, process new emails, check active bidding timers, and transition quotes across workflow statuses.
  • Amazon RDS PostgreSQL: Host database storing structured carrier data, billing logs, and vector embeddings using the pgvector extension.
  • Amazon S3: The React UI is hosted statically in an S3 Bucket. A private S3 bucket is also set up to host generated files like Bill of Ladings, invoices, and email attachments.

🧬 3. Modular Application Architecture

The application’s backend codebase is structured modularly. This makes it simple to add new router paths, plug in custom markup logic, or swapping LLM models.

graph TB
    subgraph Frontend ["Frontend UI - React/Vite"]
        UI["React Pages and State"]
        APIClient["API Client - Axios"]
        UI --> APIClient
    end

    subgraph Backend ["FastAPI Backend Application"]
        subgraph Routers ["FastAPI APIRouter Endpoints"]
            AuthRoute["auth.py - User Auth and OAuth"]
            QuotesRoute["quotes.py - Quote Management"]
            CarriersRoute["carriers.py - Carrier Management"]
            CustomersRoute["customers.py - Customer Management"]
            SimRoute["simulator.py - Round Simulation"]
            AnalyticsRoute["analytics.py - Metrics and Charts"]
            CredsRoute["email_credentials.py - SMTP settings"]
        end

        subgraph CoreServices ["Business Logic and Services"]
            Workflow["workflow.py - State Machine and Timers"]
            EmailSvc["email_service.py - SMTP and IMAP Engine"]
            AISvc["cerebras_service.py - Llama-3 Parsing and Extraction"]
            EmbedSvc["embedding_service.py - pgvector Embeddings"]
            BillingSvc["billing.py - Invoice and BOL Generation"]
            S3Storage["s3_storage.py - S3 Attachment Helper"]
        end

        subgraph DataAccess ["Database and ORM"]
            Models["models.py - SQLAlchemy Models"]
            Schemas["schemas.py - Pydantic Validation"]
            DBConnection["database.py - Database Connections"]
        end
    end

    subgraph Database ["PostgreSQL Database"]
        PGVector["pgvector Extension"]
        Tables["Relational Tables"]
    end

    %% Flow connections
    APIClient --> Routers
    
    %% Router connections to Services & Database
    QuotesRoute --> Workflow
    QuotesRoute --> EmbedSvc
    CredsRoute --> DBConnection
    AuthRoute --> DBConnection
    
    %% Services orchestration
    Workflow --> EmailSvc
    Workflow --> BillingSvc
    Workflow --> S3Storage
    
    EmailSvc --> AISvc
    EmailSvc --> S3Storage
    EmailSvc --> Workflow
    
    %% Data / Database Connections
    Workflow --> Models
    EmailSvc --> Models
    Models --> DBConnection
    DBConnection --> Tables
    EmbedSvc -.-> PGVector

🔌 4. The Email Connector Anatomy

The Email Connector is the gateway connecting our system to the external email servers. It implements a bi-directional integration:

  1. Inbound Email Processing (IMAP): Connects to the inbox, fetches unread emails, extracts attachments, extracts the Quote ID (e.g. Q-1002) using regex, parses payloads using Cerebras AI, and triggers state transitions.
  2. Outbound Email Processing (SMTP): composes styled HTML templates, injects workflow-driven parameters (like margins and bidding instructions), and dispatches emails.

Here is the architectural anatomy of how the email connector interacts with external mailboxes, AI systems, and storage buckets:

graph TD
    subgraph EmailServer ["Email Server or Sandbox"]
        Mailbox["Broker Mailbox"]
        SMTPHost["SMTP Server"]
        IMAPHost["IMAP Server"]
    end

    subgraph ConnectorAnatomy ["Email Connector Anatomy"]
        subgraph InboundFlow ["Inbound Connector IMAP"]
            IMAPPoller["IMAP Client Poller"]
            EmailParser["MIME Parser"]
            RegexRouter["Regex ID Extractor"]
            LLMParser["Cerebras AI Parser"]
            WorkflowRouter["Workflow Transition Engine"]
        end

        subgraph OutboundFlow ["Outbound Connector SMTP"]
            SMTPSender["SMTP Client Sender"]
            HTMLComposer["HTML Email Composer"]
        end
    end

    subgraph DataStore ["Database and Storage"]
        DB[("Amazon RDS Postgres")]
        S3Bucket[("S3 Attachments Bucket")]
    end

    %% Interactions
    IMAPHost -->|Fetches raw MIME| IMAPPoller
    IMAPPoller --> EmailParser
    EmailParser --> RegexRouter
    RegexRouter -->|Quote ID matched| WorkflowRouter
    RegexRouter -->|No Quote ID| LLMParser
    LLMParser -->|Extracts lane metadata| WorkflowRouter
    
    WorkflowRouter -->|Save quotes and bids| DB
    EmailParser -->|Extract PDF BOL and Attachments| S3Bucket

    HTMLComposer -->|Generates HTML payload| SMTPSender
    SMTPSender -->|Sends SMTP traffic| SMTPHost
    
    DB -->|Trigger RFQ or Proposal| HTMLComposer

Connector Operations:

  • The Mailbox Poller (IMAP): Loops through the inbox. For every email fetched, it generates a hash key. It uses a ProcessedEmail table in the database to prevent duplicate processing.
  • The Regex Router: A fast check matches string tags like Q-\d{4} in the email subject or body.
    • If a match is found: The email is classified as a reply. The system checks if it is a customer approval/rejection or a carrier bid, and updates the quote.
    • If no match is found: The email is treated as a new inquiry. The raw text is passed to Cerebras LLM to parse out location coordinates, carrier requirements, and weight.
  • The HTML Template Composer: Composes highly structured logistics documents. For carriers, it templates a bid solicitation. For customers, it templates a markup proposal showing historical lane competitiveness scores to validate the rates.

🌐 Try Out the Live Demo

You can interact with the live broker dashboard and test the automated competitive bidding rounds here: 👉 Freight Agent AWS Live Demo


🚀 How to Deploy the Serverless Stack

The stack is configured to deploy directly to AWS using the Serverless Framework (v3).

1. Build and Deploy API Gateway + Lambda

Initialize your AWS credentials locally, install the NPM plugins, and run:

npm install
npx serverless deploy --stage dev

This automatically packs the Python code into a Lambda layer, provisions the API Gateway HTTP routes, registers the EventBridge scheduler rules, and sets up execution roles.

2. Deploy Frontend to S3

The React Vite application can be built and synced to its hosting bucket using the deploy script:

./deploy_frontend.sh dev

The script resolves your AWS Account ID, compiles the frontend bundle using the correct API Gateway URL, syncs the assets to S3, and prints the public HTTP endpoint of the broker UI.


🛠️ Tech Stack Recap

  • Backend Core: Python 3.11, FastAPI, Mangum, SQLAlchemy, PostgreSQL (pgvector).
  • Serverless Infrastructure: Serverless Framework, AWS Lambda, API Gateway, Amazon S3, EventBridge.
  • AI Engine: Cerebras Cloud SDK (Llama-3.1-70b-preview) for instant completions and parsing.
  • Frontend Client: React 18, Vite, Tailwind CSS, Axios, Lucide Icons, Recharts.

Check out the full repository and set up your serverless bidding broker agent: 👉 freight-agent-aws GitHub Repository