@pixlcore/xyplug-imap-trigger
v1.0.0
Published
An IMAP email trigger plugin for the xyOps workflow automation system.
Maintainers
Readme
An IMAP trigger plugin for the xyOps Workflow Automation System. It watches an email mailbox on a schedule, launches a job when matching messages are found, and passes the parsed email data plus attachments into the job input.
Use it for inbound order processing, support queues, report ingestion, approval emails, document dropboxes, alert mailboxes, or any workflow where email arrival should start automation.
Features
- Pure Node.js /
npxplugin. - Works as a xyOps Trigger Plugin.
- Polls any IMAP-compatible mailbox on the cadence of a normal xyOps schedule.
- Defaults to unread messages with
UNSEENstyle behavior via IMAP search criteria. - Processes up to a configurable maximum number of messages per trigger run.
- Always passes
input.data.emailsas an array to the launched job. - Downloads attachments and passes them to the launched job as normal xyOps input files.
- Can optionally attach the raw
.emlmessage for archival or forensic workflows. - Supports post-processing actions: mark as read, move to folder, delete, or leave unchanged.
- Uses a xyOps Secret Vault variable for the IMAP password.
Requirements
- Node.js and
npx - Network access from the xyOps primary conductor host to your IMAP server
Secrets / Environment Variables
Create a Secret Vault in xyOps and assign this plugin to it. Add:
IMAP_PASSWORD
Enter the hostname and username directly in the plugin parameters.
Data Collection
This plugin does not collect, store, or transmit telemetry, analytics, or usage metrics. It only connects to the IMAP server you configure. Your email provider may log IMAP connections and mailbox actions according to its own policies.
How It Works
This is a schedule modifier. Add it alongside a normal xyOps schedule trigger, such as every minute, every five minutes, or hourly. The schedule decides when xyOps asks the plugin for a launch decision. This plugin then checks the configured mailbox and returns yes or no (along with the matched message data).
When matching email is found, the plugin:
- Downloads and parses up to
Maximum Messages. - Returns
launch: trueto trigger a job launch. - Passes parsed email records in
input.data.emails. - Passes attachments as xyOps input files.
- Applies the selected post-processing action.
If no matching email is found, the job is not launched.
Parameters
| Parameter | Required | Description |
|-----------|----------|-------------|
| IMAP Hostname | Yes | IMAP server hostname. |
| Username | Yes | IMAP username. |
| Port | No | IMAP TCP port. Defaults to 993. |
| Use TLS | No | Use IMAP over TLS. Enabled by default. |
| Reject Unauthorized TLS Certs | No | Reject untrusted TLS certificates. Enabled by default. |
| Timeout (sec) | No | Connection and socket timeout. Defaults to 30. |
| Mailbox | No | Mailbox folder to poll. Defaults to INBOX. |
| Search Criteria | No | IMAP search criteria as JSON. Defaults to { "seen": false }. |
| Maximum Messages | No | Maximum matching messages to process in one run. Defaults to 1. |
| Message Order | No | Process oldest or newest matching UIDs first. Defaults to oldest first. |
| Download Attachments | No | Attach email attachments to the launched xyOps job. Enabled by default. |
| Attach Raw Email | No | Also attach each raw .eml message. Disabled by default. |
| Max Body Characters | No | Maximum characters for text and HTML bodies. Defaults to 250000; 0 means no limit. |
| Post-Processing Action | No | Mark as Read, Move to Folder, Delete, or None. Defaults to Mark as Read. |
| Move to Folder | Only for move | Destination mailbox for move action. The folder must already exist. |
Search Criteria
The default search criteria is:
{
"seen": false
}That means the plugin only processes unread messages. After a successful fetch and staging step, the default post-processing action marks those messages as read so they will not be picked up again.
You can customize the search criteria in the native JSON editor. Examples:
Unread messages from one sender:
{
"seen": false,
"from": "[email protected]"
}Unread messages with a case-insensitive subject match:
{
"seen": false,
"subject": "Invoice"
}Messages received since a date:
{
"since": "2026-07-01"
}Unread Gmail messages with a specific label:
{
"seen": false,
"labels": {
"has": [ "Cool" ]
}
}For Gmail label searches like this, set Mailbox to [Gmail]/All Mail. Some Gmail labels are not exposed as IMAP folders unless they are enabled for IMAP in Gmail settings.
Post-Processing Choices
| Action | Behavior |
|--------|----------|
| Mark as Read | Adds the IMAP Seen flag after messages are staged. This is the safest default. |
| Move to Folder | Moves processed messages to another mailbox folder, such as Processed. This is best for audit trails. |
| Delete | Deletes processed messages from the mailbox. Use carefully. |
| None | Leaves messages unchanged. Useful for testing, but will reprocess the same messages repeatedly. |
Output Summary
When email is found, the launched job receives:
input.data.emails: Array of parsed email records.input.data.imap: Summary of the mailbox poll and post-processing action.input.files: Attachment files, and optionally raw.emlfiles.
Each emails array entry includes common fields such as:
uidmessageIdsubjectdatefromtoccreplyToheaderstexthtmlfiles
The files array inside each email describes the files attached to the xyOps job. The actual files are passed through xyOps as normal input files for the launched job.
General Notes
- This plugin does not create jobs by itself. It modifies launches from a normal schedule trigger.
- Trigger Plugins run on the xyOps primary conductor server, so that server needs network access to your IMAP host.
- For Gmail, Outlook, Yahoo, and similar providers, you may need an app-specific password or provider-specific IMAP settings.
- For Gmail labels that are not exposed as IMAP folders, use
[Gmail]/All Mailas the mailbox and filter bylabelsin the search criteria. Move to Folderrequires the destination mailbox to already exist.Noneis useful while testing, but it usually needs strict search criteria to avoid repeated launches.Deleteis intentionally opt-in because it removes mail from the source mailbox.- The plugin applies the post-processing action after email data and files are staged, but before xyOps launches the downstream job.
Local Testing
When invoked by xyOps, the plugin expects a single JSON document on STDIN using the xyOps Wire Protocol. You can simulate this locally by piping JSON into node index.js.
Example test using an environment variable for the password:
echo '{"xy":1,"type":"trigger","items":[{"timezone":"America/Los_Angeles","now":1783180800,"dargs":{"year":2026,"month":7,"day":4,"weekday":6,"hour":9,"minute":0},"params":{"hostname":"imap.example.com","username":"[email protected]","mailbox":"INBOX","search_criteria":{"seen":false},"max_messages":2,"post_action":"mark_read","download_attachments":true},"job":{"id":"emexample","title":"Process Incoming Email"}}]}' | IMAP_PASSWORD=REPLACE_ME node index.jsExample test using the secrets object, which mirrors what xyOps provides:
{
"xy": 1,
"type": "trigger",
"secrets": {
"IMAP_PASSWORD": "REPLACE_ME"
},
"items": [
{
"timezone": "America/Los_Angeles",
"now": 1783180800,
"dargs": {
"year": 2026,
"month": 7,
"day": 4,
"weekday": 6,
"hour": 9,
"minute": 0
},
"params": {
"hostname": "imap.example.com",
"username": "[email protected]",
"mailbox": "INBOX",
"search_criteria": {
"seen": false
},
"max_messages": 2,
"order": "oldest",
"download_attachments": true,
"post_action": "mark_read"
},
"job": {
"id": "emexample",
"title": "Process Incoming Email"
}
}
]
}Run it like this:
cat sample.json | node index.jsExample response when no matching messages are present:
{
"xy":1,
"items": [
{ "launch":false }
]
}Example response shape when a matching message is found:
{
"xy": 1,
"items": [
{
"launch": true,
"data": {
"emails": [
{
"mailbox": "INBOX",
"uid": 101,
"subject": "Daily Report",
"from": {
"name": "Reports",
"address": "[email protected]"
},
"to": [
{
"name": "",
"address": "[email protected]"
}
],
"text": "Report attached.",
"html": "",
"files": [
{
"type": "attachment",
"filename": "email-101-attachment-1-report.csv",
"originalFilename": "report.csv",
"mimeType": "text/csv",
"size": 2048
}
]
}
],
"imap": {
"mailbox": "INBOX",
"count": 1,
"postAction": "mark_read",
"moveFolder": ""
}
},
"files": [
{
"path": "/tmp/xyplug-imap-example/email-101-attachment-1-report.csv",
"delete": true
}
]
}
]
}The real plugin output is compacted onto one line, as required by the xyOps Wire Protocol.
License
MIT
