How to Filter Inbound Emails Before Processing

Route emails to the right handler based on sender, subject, or any field in the JSON payload. Use per-address routing and handler-level filtering to build precise inbound email pipelines.

Table of Contents
  1. Overview
  2. Prerequisites
  3. Step-by-Step Instructions
  4. Code Example
  5. Common Pitfalls

Overview

Not every inbound email should trigger the same action. A support email needs a ticket created. A lead notification needs a CRM record. An invoice needs to be forwarded to accounting. Filtering and routing inbound emails to the right handler is as important as parsing them.

JsonHook supports two levels of filtering:

  • Address-level routing: Create separate inbound addresses for each email category. Each address has its own webhook URL, so routing happens at the network level — support emails go to the support webhook, order emails go to the order webhook, with no shared handler logic.
  • Handler-level filtering: Within a single webhook handler, inspect payload fields (email.from, email.subject, email.to, custom headers) and dispatch to different processing functions based on the content.

Address-level routing is simpler, more maintainable, and more reliable — it should be your default approach. Handler-level filtering is useful when the routing decision depends on the email content (e.g., routing based on subject keywords).

Prerequisites

Requirements for building a filtered email pipeline:

  • A JsonHook account with enough address quota for your routing plan (Starter: 5 addresses, Pro: unlimited)
  • A clear mapping of email categories to webhook endpoints
  • Understanding of how your email sources deliver to different addresses (e.g., different To addresses on a contact form, forwarding rules in your ESP)

Build Precise Email Routing Pipelines

One address per flow. Every email to the right handler. Start free.

Get Free API Key

Step-by-Step Instructions

Build a filtered inbound email pipeline:

  1. Map your email flows. List every email category you receive and what action each requires. For example: support@ → create ticket, orders@ → process order, leads@ → create CRM record.
  2. Create one JsonHook address per category. Each address points to a dedicated webhook handler:
    # support address
    POST /v1/addresses { "webhookUrl": "https://app.com/webhooks/support", "label": "Support emails" }
    # orders address
    POST /v1/addresses { "webhookUrl": "https://app.com/webhooks/orders", "label": "Order emails" }
  3. Route email sources to the appropriate address. Update your contact form, ESP settings, and domain forwarding rules.
  4. Within each handler, add content-based filtering for edge cases:
    if (!email.from.endsWith("@trusted-supplier.com")) {
      console.log("Unexpected sender — skipping");
      return res.sendStatus(200); // still return 200 to acknowledge
    }
  5. Handle unrecognized emails gracefully. Log them with their full payload for manual review rather than discarding silently.

Code Example

A single webhook handler that dispatches based on recipient address and subject content:

import express from "express";
import crypto from "crypto";

const app = express();
app.use(express.raw({ type: "application/json" }));

const DISPATCH: Record<string, (email: any) => Promise<void>> = {
  "[email protected]": handleSupport,
  "[email protected]":  handleOrder,
  "[email protected]":   handleLead,
};

app.post("/webhooks/all", async (req, res) => {
  const sig = req.headers["x-jsonhook-signature"] as string;
  const expected = crypto
    .createHmac("sha256", process.env.JSONHOOK_SECRET!)
    .update(req.body).digest("hex");
  if (sig !== expected) return res.sendStatus(401);

  const { email } = JSON.parse(req.body.toString());

  // Route by recipient
  const recipient = email.to[0]?.toLowerCase();
  const handler = DISPATCH[recipient];

  if (handler) {
    await handler(email);
  } else {
    // Fallback: filter by subject keyword
    if (/unsubscribe/i.test(email.subject)) {
      await handleUnsubscribe(email);
    } else {
      console.warn("No handler for email to:", recipient);
    }
  }

  res.sendStatus(200);
});

Common Pitfalls

Filtering pitfalls to avoid:

  • Routing by subject instead of recipient address. Subject lines change without notice. Recipient address routing (using dedicated JsonHook addresses) is far more reliable than subject-based dispatch.
  • Returning a non-2xx code for filtered emails. If you decide to skip processing an email, still return 200. Returning 4xx or 5xx causes JsonHook to retry, flooding your logs with unnecessary redelivery attempts.
  • Not logging filtered emails. Emails that do not match any filter condition should be logged with their deliveryId so you can investigate unexpected traffic patterns.
  • Case-sensitive sender matching. Email addresses and domains can be mixed case. Always normalize to lowercase before comparison: email.from.toLowerCase().
  • Blocking on slow filtering decisions. If your filter requires a database lookup (e.g., "is this sender in our allowlist?"), cache the allowlist in memory or use a fast key-value store to avoid slowing down the webhook handler.

Frequently Asked Questions

Can I use regex to filter emails by subject?

Yes. In your webhook handler, apply a regex to email.subject before dispatching to a processor. This works well for structured subject lines like order confirmations or automated alerts. For human-written subjects, regex is fragile — prefer filtering by sender address or recipient address when possible.

Can I configure server-side filtering rules in JsonHook without writing a handler?

JsonHook delivers all emails that arrive at an inbound address to the configured webhook URL — server-side filtering rules are not currently available. All filtering logic lives in your webhook handler. For no-code filtering, route through Zapier or Make which support conditional steps before reaching your application.

How do I handle spam that arrives at my inbound address?

JsonHook performs basic spam filtering at the SMTP level. For additional spam protection in your handler, check the email.headers for spam scores (many mail servers add X-Spam-Score headers), validate that the sender domain has valid SPF/DKIM records (check email.headers for authentication results), and apply your own allowlist/blocklist logic.

How many addresses can I create for routing purposes?

The free tier includes 1 address, Starter includes 5, and Pro includes unlimited addresses. For most routing use cases, 5 addresses covers the common email categories. If you need per-customer or per-tenant inbound addresses at scale, the Pro plan is designed for that use case.