How to Import Emailed CSV Files into MongoDB Automatically
Build a Spojit workflow that watches a Mailhook address, fetches the attached CSV file, parses its rows, and inserts them into a MongoDB collection without anyone touching a spreadsheet.
What This Integration Does
Many teams receive recurring data files by email: a supplier sends a price list every morning, a partner forwards a nightly export, or an internal system mails a CSV report on a schedule. Re-keying those rows into a database is slow and error-prone. This workflow turns the inbox into an automated loading dock: a file arrives, and seconds later its contents are queryable in MongoDB. You point any sender at a dedicated Spojit address, attach a CSV, and the rows land in your collection ready for reporting or downstream automation.
The run is push-based. A Mailhook trigger gives you a unique address, and any mail to it starts a run within seconds (no mailbox or OAuth to manage). The trigger exposes the message and its attachment references as {{ input }}; an Attachment node fetches the actual CSV bytes, the csv connector turns those bytes into JSON rows, and a MongoDB connector inserts them. Each email is deduplicated per message, so the same file resent twice only fires one run, and re-running an execution simply re-imports the same parsed rows. State left behind is one batch of documents per matching email.
Prerequisites
- A MongoDB connection added under Connections, with the target database set and write access to the collection you will load into.
- Knowledge of the CSV layout you will receive (column headers, delimiter) so you can map the rows cleanly.
- A target collection name in mind, for example
imported_rows. MongoDB creates the collection on first insert if it does not exist. - The csv, json, and encoding utility connectors, which are built in and need no authentication.
- The list of senders or systems that will email the file, so you can lock the trigger down with a From allowlist.
Step 1: Add a Mailhook trigger and generate the address
On a new workflow, open the Trigger node and set Trigger Type to Mailhook. Optionally set an Address prefix (1 to 24 characters, default mh) such as csv-import, then click Generate email address. Spojit produces a unique address of the form csv-import-<random16>@mailhook.spojit.com. Copy it and point your sender or forwarding rule at it. To keep stray mail out, add the sending addresses under From allowlist and, if the report always shares a subject line, add a Subject regex such as ^Daily Export. The trigger fires whether the address is in To, Cc, or Bcc. Its output is available downstream as {{ input }}, including {{ input.subject }}, {{ input.from }}, and the attachment references in {{ input.attachments }}.
Step 2: Fetch the CSV with an Attachment node
Add an Attachment node connected after the trigger. This node only works with a Mailhook trigger, and it fetches the real bytes behind the references the trigger listed. Set Mode to Single so the node returns the first matching file as one object. Restrict it to spreadsheets with a Filename pattern of *.csv, and optionally a Content type filter of text/csv. Turn on Fail if no attachment matches so a mistakenly empty email stops cleanly instead of inserting nothing. Name the output variable attachment. In Single mode the node returns:
{
"filename": "daily-export.csv",
"contentType": "text/csv",
"size": 18432,
"content": "<base64-encoded file bytes>"
}
The content field is base64, which the next step decodes into plain CSV text.
Step 3: Decode the file to CSV text
Add a Connector node in Direct mode using the encoding connector and the base64-decode tool. Map its input to {{ attachment.content }} so the base64 bytes become readable CSV text. Name the output variable decoded. Keeping the decode as its own step makes the workflow easy to follow and lets you inspect the raw text in the run history if a file ever arrives malformed. The decoded text is now available as {{ decoded.result }} for the parser.
Step 4: Parse the CSV into JSON rows
Add another Connector node in Direct mode using the csv connector and the parse tool. Set the csv field to {{ decoded.result }}. Leave delimiter blank to auto-detect, or set it explicitly to , if your file uses a fixed delimiter. Because the first row holds your column names, the parser treats it as headers and returns an array of objects keyed by those headers. Name the output variable rows. A file like:
sku,name,price
A-100,Widget,9.99
A-200,Gadget,14.50
becomes structured records you can insert directly:
[
{ "sku": "A-100", "name": "Widget", "price": "9.99" },
{ "sku": "A-200", "name": "Gadget", "price": "14.50" }
]
If you need to coerce types, drop empty rows, or rename columns before loading, add the json connector with tools such as pick, omit, or set between this step and the insert, or use a Transform node to reshape each record.
Step 5: Insert the rows into MongoDB
Add a final Connector node in Direct mode using your MongoDB connection and the insert-documents tool. Set collection to your target, for example imported_rows, and set the documents field to the parsed array from the previous step. The tool accepts one or more documents and inserts the whole batch in a single call:
{
"collection": "imported_rows",
"documents": {{ rows.result }}
}
The tool returns an insertedCount so you can confirm how many rows landed. The database is taken from your MongoDB connection, so you do not repeat it in the node. If the collection does not exist yet, MongoDB creates it on the first insert.
Step 6: Reply with a load summary (optional)
To close the loop, add a Send Email node that confirms the import to whoever sent the file. Mailhook runs are always asynchronous and send no automatic reply, so use the trigger's reply address. Set Recipients to {{ input.replyTo }}, the Subject to Imported {{ attachment.filename }}, and a Body such as Loaded {{ rows.result }} rows into MongoDB. The Send Email node uses Spojit's built-in mail service and needs no connection, though external recipients must be on your organization's allowlist under Settings > General > Email recipients.
Tips
- Attachment limits default to 10 MB per file and 25 MB per run. For very large exports, split the file at the source or have the sender compress and chunk it.
- Received emails are retained for 30 days, so you can re-open a recent run in the execution history and re-run it if an import needs to be replayed.
- If a column should be a number or date rather than text, add a json
setstep or a Transform node before the insert so values store with the right type for querying. - Use the From allowlist and Subject regex on the trigger to make sure only the intended report starts a run; this keeps junk and replies out of your collection.
Common Pitfalls
- Feeding
{{ attachment.content }}straight into the CSV parser fails, because that field is base64. Always decode it with the encodingbase64-decodetool first. - If the file has no header row, the parser still treats the first line as headers. Either ask the sender to include headers or supply your own mapping in a Transform node.
- Forgetting to enable Fail if no attachment matches means an email with no CSV silently produces zero rows; turn it on so the run stops visibly instead.
- Re-importing the same file appends a new batch of documents. If you need each row to be unique, add an
update-documentsupsert step keyed on a stable field instead of a blind insert, or clear the collection first.
Testing
Before pointing production senders at the address, email a small sample CSV with three or four rows to the generated Mailhook address from an allowlisted account. Open the run in the execution history and step through each node: confirm the Attachment node returned the right filename and a non-empty content, that the decode produced readable text, and that the parser's rows output has the expected shape. Check the insertedCount from the MongoDB step and run a quick find-documents query against the collection to verify the rows landed correctly. Once the small batch looks right, switch to your real file and senders.