How to Filter and Deduplicate Vendor Notification Emails with a Mailhook

Point your vendors' notification emails at a Spojit Mailhook, screen them with a From allowlist and a Subject regex, skip any duplicate you have already seen using a MongoDB lookup, and post a clean summary to Slack.

What This Integration Does

Vendors send a constant stream of automated notifications: shipment confirmations, stock alerts, backorder notices, price changes. They arrive at all hours, often from a handful of known sender addresses, and the same message can be re-sent or forwarded more than once. This workflow gives those emails a single dedicated landing address, throws away anything that is not from an approved vendor or does not match the subject you care about, and refuses to act on a message twice. The result is that your team sees one Slack post per genuine vendor event instead of a noisy inbox.

The run model is push-based. A Mailhook trigger generates a unique address, and any email sent to it starts a run within seconds with no mailbox or polling involved. The From allowlist and Subject regex on the trigger drop unwanted mail before a run even begins. Inside the run, a MongoDB count-documents lookup against a small ledger collection decides whether this message has been processed before; if it has, a Condition node ends the branch quietly. If it is new, you record its message id and send the Slack summary, so re-deliveries of the same email become no-ops. Each Mailhook message is also deduplicated by Spojit at the source, so the MongoDB ledger is a second, durable guard that survives across address rotations and longer time windows.

Prerequisites

  • A workspace on Spojit where you can open the Workflow Designer and add a Mailhook trigger.
  • A MongoDB connection (added under Connections -> Add connection) with read and write access to a database where you can keep a small ledger collection, for example vendor_notifications.
  • A Slack connection authorized to post to your target channel, and the channel id or name you want to notify.
  • The list of vendor sender addresses you trust (for the From allowlist) and a sense of the subject lines you care about (for the Subject regex).
  • Somewhere to point the vendor mail: either a vendor portal field you control, or a forwarding rule on a mailbox that already receives these notifications.

Step 1: Create the Mailhook trigger and generate its address

Add a Trigger node and set Trigger Type to Mailhook. Set an optional Address prefix (1 to 24 characters) such as vendors so the address is recognizable, then click Generate email address. Spojit produces a unique address of the form vendors-<random16>@mailhook.spojit.com. Copy it and point your vendor notifications at it, either by entering it in the vendor portal or by adding a forwarding rule. The trigger fires whether the address is in To, Cc, or Bcc. Every message is exposed to later steps as {{ input }}, including {{ input.from }}, {{ input.subject }}, {{ input.text }}, {{ input.messageId }}, and {{ input.replyTo }}.

Step 2: Add the From allowlist and Subject regex filters

On the same Mailhook trigger, fill in the From allowlist with the vendor addresses you trust, for example orders@acme-supply.com and noreply@globex-logistics.com. Mail from any other sender never starts a run. Then set the Subject regex to match only the notifications you act on. For shipment and backorder notices a pattern like the one below keeps the relevant mail and drops newsletters or out-of-office replies:

^(Shipment|Backorder|Stock Alert)\b.*

Because both filters run before the workflow executes, filtered mail costs nothing and never appears in your execution history. Keep the regex deliberately broad at first, then tighten it once you see real subjects come through.

Step 3: Look up the message in MongoDB to detect duplicates

Add a Connector node in Direct mode, choose the MongoDB connector, and select the count-documents tool. Point it at your ledger collection (for example database operations, collection vendor_notifications) and filter on the unique message id from the trigger:

{
  "database": "operations",
  "collection": "vendor_notifications",
  "filter": { "messageId": "{{ input.messageId }}" }
}

The tool returns a count. Store the node's output in a variable such as seen. A count of 0 means this is a new notification; anything higher means you have already processed it. Using {{ input.messageId }} as the dedup key is reliable because each email carries a stable message id that survives forwarding and re-delivery.

Step 4: Branch on the duplicate check with a Condition node

Add a Condition node that tests whether the count from Step 3 is greater than zero, for example {{ seen.count }} > 0. Connect the true branch to nothing further so duplicates end the run quietly. Connect the false branch onward to the record-and-notify steps. This keeps the workflow idempotent: if a vendor re-sends the same shipment confirmation three times, only the first run reaches Slack, and the rest stop at this fork.

Step 5: Record the message id so future copies are skipped

On the false branch, add a Connector node in Direct mode using the MongoDB connector with the insert-documents tool. Write one ledger row capturing the message id and a few useful fields so the count in Step 3 finds it next time:

{
  "database": "operations",
  "collection": "vendor_notifications",
  "documents": [
    {
      "messageId": "{{ input.messageId }}",
      "from": "{{ input.from }}",
      "subject": "{{ input.subject }}",
      "receivedAt": "{{ input.receivedAt }}"
    }
  ]
}

Insert the ledger row before posting to Slack so that even if two copies of the same email arrive within the same second, the first run to reach this step claims the message id. For an extra guard against exact races, create a unique index on messageId in MongoDB so a second insert of the same id fails fast instead of producing a duplicate notification.

Step 6: Post a clean summary to Slack

Add a final Connector node in Direct mode using the Slack connector with the send-message tool. Set the channel and compose a message from the trigger variables so each post is one tidy line per vendor event:

{
  "channel": "#vendor-alerts",
  "text": "New vendor notification from {{ input.from }}\nSubject: {{ input.subject }}\nReceived: {{ input.receivedAt }}"
}

If you want a short human-readable digest instead of the raw subject and body, switch this Connector node to Agent mode with a Response Schema, or add a Transform node before it to reshape {{ input.text }} into the summary you post. Because Mailhook runs are always asynchronous, there is no reply to the sender from the trigger itself; if you ever need to acknowledge the vendor, add a Send Email node addressed to {{ input.replyTo }}.

Tips

  • Keep the ledger collection lean: store only the message id and a handful of metadata fields, and consider a periodic cleanup of old rows since Spojit retains the underlying received emails for 30 days.
  • Add a unique index on messageId in MongoDB. The count-documents check handles the common case, and the index closes the rare same-instant race that two simultaneous deliveries could open.
  • Use a descriptive Address prefix per vendor program (for example vendors or logistics) so you can tell at a glance where mail is being routed if you run several Mailhook workflows.
  • Ask Miraxa, the intelligent layer across your automation, to scaffold the branch for you with a prompt like "Add a Condition node that checks if {{ seen.count }} is greater than 0 and connect the false branch to a MongoDB insert-documents node, then a Slack send-message node," then fine-tune the fields in the properties panel.

Common Pitfalls

  • Anchoring the Subject regex too tightly. A pattern like ^Shipment confirmed$ rejects real subjects that carry an order number. Test against actual subjects and prefer a broad prefix match.
  • Forwarding strips or rewrites headers on some mail systems. If forwarded copies arrive with a different message id, dedup will treat them as new. Where possible, point vendors directly at the Mailhook address rather than forwarding through a mailbox.
  • Inserting the ledger row after the Slack post instead of before it. Record the message id first so a duplicate that lands mid-run cannot slip past the count check.
  • Rotating the address without updating the vendor. Using Regenerate address kills the old address instantly, so any vendor still sending to it silently stops triggering runs.

Testing

Before pointing real vendors at it, send yourself a test email to the generated Mailhook address from one of the allowlisted senders with a subject that matches your regex. Confirm a run appears in the execution history, the MongoDB count-documents step returns 0, the ledger row is inserted, and the Slack message lands. Then send the exact same email again: the second run should reach the Condition node and stop, with no new Slack post and no second ledger row. Finally, send a message from an address that is not on the allowlist and confirm no run starts at all. Once these three cases behave, widen the allowlist and regex to your full vendor set.

Learn More

Did this answer your question? Thanks for the feedback There was a problem submitting your feedback. Please try again later.