How to Build a Searchable Archive from Forwarded Email Documents with a Mailhook
Give your team a single email address to forward documents to, and let Spojit embed every attachment into a persistent Knowledge collection so the whole workspace can search it later with AI.
What This Integration Does
Most useful documents arrive as email attachments: vendor specs, signed contracts, policy PDFs, meeting notes, and reports that staff forward to each other and then lose track of. This workflow turns a forward-this-here habit into a living, searchable archive. You publish one Spojit Mailhook address, staff forward (or set a mail rule to forward) any document to it, and every attachment is automatically embedded into a persistent Knowledge collection. Because Knowledge collections are workspace-scoped, any other workflow can query that archive later, so the documents your team forwarded today become the answers Miraxa retrieves for them next month.
The run model is push-based and per-message. A Mailhook trigger fires within seconds of mail landing, with no mailbox to poll and no OAuth to maintain. Each forwarded email starts its own run: the Attachment node fetches the bytes of the matching files, a Loop walks them, and a Knowledge node in Embed mode writes each document into the same persistent collection. The collection is the durable state this workflow leaves behind: it grows with every email and persists across runs, so re-running or replaying never wipes it. Spojit deduplicates per message, so the same forwarded email does not double-embed.
Prerequisites
- A workspace where you can create workflows in the Spojit Workflow Designer.
- A persistent Knowledge collection to write into. Create one first from the Knowledge section of the sidebar with New Collection, give it a name (for example
document-archive), and note the embedding model it is fixed to at creation. - The ability to forward mail to an external address, or a mail rule on your existing inbox that forwards documents to the address Spojit generates.
- Optional: a short list of sender addresses you trust, if you want to restrict who can feed the archive.
- No connection or OAuth is required for the Mailhook trigger, the Attachment node, or the Knowledge node. The pdf utility connector used for optional cleanup is built in and needs no auth.
Step 1: Add a Mailhook trigger and generate the address
Create a new workflow and open the trigger node. Set Trigger Type to Mailhook. Optionally set an Address prefix (1 to 24 characters, default mh) so the address is recognizable, for example docs. Click Generate email address and Spojit produces a unique address like docs-a1b2c3d4e5f6g7h8@mailhook.spojit.com. Copy it and share it with your team, or point a forwarding rule at it. Any mail sent to this address, whether the address is in To, Cc, or Bcc, starts a run. The trigger output is available as {{ input }} with fields such as {{ input.subject }}, {{ input.from }}, {{ input.replyTo }}, and {{ input.attachments }}, where each attachment reference is { id, filename, contentType }.
Step 2: Restrict who can feed the archive (optional)
Still on the Mailhook trigger, use the optional From allowlist to accept mail only from known senders (your staff domain, for example), and the optional Subject regex to require a marker like ^\[ARCHIVE\] in the subject. Mail that does not match the filters is ignored, so accidental or external mail never reaches your collection. If you ever need to retire the public address, use Regenerate address on the trigger: the old address dies instantly and a new one is issued.
Step 3: Fetch the attachment bytes with an Attachment node
Add an Attachment node after the trigger. This node only works in Mailhook workflows; the designer refuses to save it without a Mailhook trigger. Set Mode to Multiple so one email carrying several documents is fully captured. Narrow it to the files you want to archive with the Filename pattern field (a glob such as *.pdf) or the Content type filter (for example application/pdf, application/vnd.openxmlformats-officedocument.wordprocessingml.document). Use Min/Max size to skip tiny signature images, and leave Fail if no attachment matches off so a forwarded email with no qualifying file simply ends the run quietly. In Multiple mode the output is:
{
"attachments": [
{ "filename": "vendor-spec.pdf", "contentType": "application/pdf", "size": 84213, "content": "JVBERi0xLjc..." }
],
"count": 1,
"totalBytes": 84213
}
Each item carries filename, contentType, size, and content (base64). Keep in mind the default limits of 10 MB per attachment and 25 MB per run, and that received emails are retained for 30 days.
Step 4: Loop over the attachments
Add a Loop node in ForEach mode and point it at {{ attachment.attachments }} (using the Attachment node output variable). Everything inside the loop body runs once per file, with the current item available as the loop variable (for example {{ item }}), so a single email that bundles five PDFs results in five documents in the archive. This keeps each document a distinct, separately searchable entry in the collection rather than one merged blob.
Step 5: Embed each document into the persistent collection
Inside the loop body, add a Knowledge node and set its mode to Embed. Configure it as follows:
- Collection: pick your persistent collection, for example
document-archive(do not pick Transient here, because you want the documents to survive after the run). - File Name: set a stable, unique name per document so the archive stays organized and re-forwards overwrite rather than duplicate, for example
{{ input.receivedAt }}-{{ item.filename }}. - Document Type: choose the type that matches the file, such as PDF or Word. If a single mailhook can receive mixed types, branch on
{{ item.contentType }}with a Condition node and set the matching Document Type on each path. - Document Input: reference the base64 bytes from the loop item,
{{ item.content }}. - Embedding Model: leave it as the collection default. Always embed with the same model the collection was created with, so later queries line up.
- Output Variable: capture it (chunk count plus metadata) if you want to log how many chunks each document produced.
The Knowledge node splits the document into searchable chunks and writes them into the collection. Because File Name overwrites an existing entry of the same name, a clean naming scheme keeps the archive free of accidental duplicates.
Step 6: Confirm receipt back to the sender (optional)
After the loop, add a Send Email node to acknowledge the forward. Mailhook runs are always asynchronous, so the sender gets no automatic reply; this node closes that gap. Set Recipients to {{ input.replyTo }}, give it a Subject like Archived: {{ input.subject }}, and a short Body confirming how many files were stored, for example We filed {{ attachment.count }} document(s) into the archive.. Send Email uses Spojit's built-in mail service and needs no connection, though external recipients must be on your org allowlist under Settings -> General -> Email recipients. To reply from your own domain instead, swap in the Resend or SMTP connector.
Step 7: Query the archive from any workflow
Once the archive is filling up, build a second workflow to search it. Use any trigger (a Manual trigger to test, or a Webhook so a help desk tool can ask), then add a Knowledge node in Query mode. Set Collection to the same document-archive, write a natural-language Prompt such as What does the latest vendor spec say about return windows?, set Result Count (default 5), optionally attach a Response Schema to force structured JSON, and capture the Output Variable. Because the collection is workspace-scoped, this query workflow reads the very documents your team forwarded, no re-upload required.
Tips
- Use the pdf connector in a Connector node (Direct mode) before embedding when forwards include cover pages:
remove-pagesorextract-pagescan strip boilerplate, andget-infolets you skip empty files. Trim noise out before it becomes chunks. - Name embedded documents with a sortable prefix like
{{ input.receivedAt }}-{{ item.filename }}so the collection's document table stays readable and re-forwards overwrite cleanly. - Keep the Subject regex filter narrow when the address is shared widely; it is the cheapest way to stop newsletters and out-of-office replies from polluting the archive.
- If you only ever expect one document per email, set the Attachment node Mode to
Singleand skip the Loop; you then reference{{ attachment.content }}directly in the Knowledge node.
Common Pitfalls
- Picking Transient instead of a persistent collection in the Knowledge node throws the documents away when the run ends. Transient is for one-off embed-then-query-in-the-same-run jobs; for a durable archive you must select a named persistent collection.
- Mixing embedding models breaks search. The collection's embedding model is fixed at creation, so leave the Knowledge node Embedding Model on the default and use that same model when querying.
- Forgetting the Document Type, or setting it wrong for a mixed-format mailhook, produces poor or empty chunks. Branch on
{{ item.contentType }}and set the matching type per path. - Oversized forwards silently drop files: attachments over 10 MB or a run over 25 MB hit the defaults. Watch
{{ attachment.totalBytes }}and split very large bundles across multiple emails. - Reusing the same static File Name for every document makes each new forward overwrite the previous one. Always template the file name so distinct documents stay distinct.
Testing
Before publishing the address widely, validate on a small scope. Forward a single known PDF to the generated mailhook address, then open the run in execution history and confirm the Attachment node returned one item with a non-empty content and the Knowledge node reported a chunk count above zero. Open your collection in the Knowledge sidebar and check the document table shows the file with status READY. Then run your query workflow with a question whose answer is in that PDF and confirm the result cites it. Only once that round trip works should you hand the address to the wider team or wire up a forwarding rule.
Learn More
- Setting Up a Mailhook Trigger
- Using Knowledge Nodes
- Uploading Documents to a Collection
- Querying Your Knowledge Base
- How to Auto-Index Incoming Emails into Your Knowledge Base
- How to Build a Searchable Knowledge Base from PDF Documents
- Mailhook trigger documentation
- Attachment node documentation
- Knowledge collections and RAG documentation