How to Configure Email Operations Using Probe's SMTP and IMAP Plugins
Probe configures email operations by treating SMTP and IMAP as separate plugin actions that communicate via HashiCorp go-plugin, requiring specific YAML parameters in the with block to send mail or query mailboxes.
The linyows/probe repository implements email automation through standalone Go binaries that handle protocol-specific logic. When you configure email operations using Probe's SMTP and IMAP plugins, you define workflow steps that spawn these plugins to transmit messages or inspect mailboxes, with results feeding back into the workflow engine as structured data.
Architecture of Probe's Email Plugins
Probe implements email capabilities as plugin actions rather than built-in functions. The core workflow engine communicates with SMTP and IMAP functionality through HashiCorp go-plugin, isolating protocol complexity into separate binaries.
Plugin Entry Points
Each plugin follows an identical interface defined in actions/smtp/main.go and actions/imap/main.go:
| Plugin | Entry File | Core Struct | Run Method |
|---|---|---|---|
| SMTP | actions/smtp/main.go |
type Action struct { log hclog.Logger } |
func (a *Action) Run(args []string, with map[string]any) (map[string]any, error) |
| IMAP | actions/imap/main.go |
type Action struct { log hclog.Logger } |
func (a *Action) Run(args []string, with map[string]any) (map[string]any, error) |
Both Run methods execute a consistent five-step pattern:
- Validate that the
withmap contains required parameters (SMTP requiresaddr,from,to; IMAP requireshost,username,password). - Log truncated input using
probe.TruncateMapStringAnyfor security. - Create callbacks via
mail.WithBefore/WithAfterorimap.WithBefore/WithAfterto hook into lifecycle events. - Delegate protocol work to library code—SMTP calls
mail.Sendfrommail/mail.go, while IMAP callsimap.Requestfromimap/client.go. - Return a
map[string]anythat the workflow engine converts to step outputs accessible via{{outputs.<step>.field}}.
SMTP Implementation Details
The SMTP plugin wraps Go's net/smtp library through the abstraction in mail/smtp.go. The mail.Send function in mail/mail.go orchestrates the transmission:
- Connection:
Dialestablishes TCP, upgrading to TLS if the underlying connection implements*tls.Conn. - Authentication: Optional STARTTLS and AUTH mechanisms negotiate after connection.
- Transmission: The client loops over
MessageCountto issueMAIL FROM,RCPT TO, andDATAcommands. - Enrichment: Each message receives a unique
Message-IDviagenMsgID, and subjects automatically append a hash ID throughappendIDtoSubject.
IMAP Implementation Details
The IMAP plugin builds on emersion/go-imap/v2 via imap/client.go. The NewReq function supplies secure defaults: port 993, TLS enabled, 30-second timeout, and strict host checking.
The request flow executes sequentially:
- Dial: Uses
imapclient.DialTLSorimapclient.DialInsecurebased on configuration. - Authenticate: Login with the provided
UsernameandPassword. - Execute: The
ExecCommandsdispatcher runs each command from the workflow (e.g.,Select,Search,Fetch).
Helper methods translate workflow syntax into go-imap structures:
parseSequenceSethandles message sequences.parseUIDSetmanages UID ranges.parseFetchItemsandparseBodySectionconvert expressions likeBODY[HEADER.FIELDS (FROM TO)]into library-specific types.
Configuring SMTP Operations
To send email, define a workflow step using uses: smtp and provide the required parameters in the with block.
Basic SMTP Configuration
name: Send Test Email
jobs:
- name: Email
steps:
- name: Send Notification
uses: smtp
with:
addr: smtp.example.com:587
from: sender@example.com
to: recipient@example.com
subject: Probe Test Email
body: |
Hello,
This email was sent via Probe's SMTP plugin.
my-hostname: localhost
test: res.code == 0 && res.sent == 1
Required parameters:
addr: Server address including port (e.g.,smtp.gmail.com:587).from: Envelope sender address.to: Envelope recipient address.
Optional parameters:
my-hostname: Defaults to "localhost" for the SMTP HELO/EHLO command.usernameandpassword: For AUTH LOGIN/PLAIN.tls: Boolean to enable STARTTLS.
The test assertion validates that res.sent equals the number of messages transmitted, confirming successful delivery through mail.Send.
Configuring IMAP Operations
IMAP configuration requires connection details and a sequence of commands to execute against the mailbox.
IMAP Mailbox Inspection
name: Check InBOX for Alerts
jobs:
- name: IMAP
steps:
- name: List Unseen Mail
uses: imap
with:
host: imap.example.com
port: 993
username: user@example.com
password: "{{env.IMAP_PASSWORD}}"
tls: true
timeout: 30s
strict_host_check: true
commands:
- name: select
mailbox: INBOX
- name: search
criteria:
since: today
flags: ["unseen"]
- name: fetch
sequence: "*"
dataitem: "BODY[HEADER.FIELDS (FROM TO SUBJECT DATE)]"
test: res.code == 0 && res.data.search.count > 0
Connection parameters:
hostandport: Server endpoint (defaults to 993 with TLS).usernameandpassword: Authentication credentials.tls: Enable TLS encryption (default: true).strict_host_check: Validate TLS certificates against the hostname.
Command structure:
Each item in the commands list maps to the imap.Command struct in imap/client.go:
select: Opens a mailbox (e.g.,INBOX,Sent).search: Queries messages using criteria likesince,flags, ortext.fetch: Retrieves message data;sequencespecifies ID ranges (*for all), anddataitemdefines the fetch attribute.
Results populate res.data.<command-name>, allowing assertions like res.data.search.count to verify message quantities.
Chaining SMTP and IMAP Workflows
Probe workflows can verify end-to-end email delivery by combining both plugins using the needs dependency syntax.
name: Notify and Verify Delivery
jobs:
- name: Notify
steps:
- name: Send Alert
uses: smtp
with:
addr: smtp.example.com:587
from: alerts@example.com
to: ops@example.com
subject: "Daily Build Completed"
body: "Build finished at {{unixtime()}}."
test: res.sent == 1
- name: Verify
needs: [Notify]
steps:
- name: Confirm Receipt
uses: imap
with:
host: imap.example.com
port: 993
username: ops@example.com
password: "{{env.IMAP_PASSWORD}}"
commands:
- name: select
mailbox: INBOX
- name: search
criteria:
since: "1 hour ago"
text: "Daily Build Completed"
- name: fetch
sequence: "*"
dataitem: "BODY[HEADER.FIELDS (FROM SUBJECT DATE)]"
test: res.code == 0 && res.data.search.count > 0
The needs: [Notify] clause ensures the IMAP verification step only executes after the SMTP plugin reports successful transmission, enabling automated delivery confirmation.
Summary
- Probe isolates email protocols into standalone plugins communicating via HashiCorp go-plugin, with entry points at
actions/smtp/main.goandactions/imap/main.go. - SMTP configuration requires
addr,from, andtoparameters in thewithblock, delegating transmission logic tomail.Sendinmail/mail.go. - IMAP configuration requires
host,username, andpassword, executing commands throughimap.Requestinimap/client.gousing the emersion/go-imap/v2 library. - Both plugins return
map[string]anyresults that become workflow outputs accessible via{{outputs.<step>.field}}notation. - Workflow dependencies (
needs) enable multi-step validation, such as sending via SMTP then confirming receipt via IMAP.
Frequently Asked Questions
What parameters are required to configure the SMTP plugin?
The SMTP plugin requires three parameters in the with block: addr (server host:port), from (sender address), and to (recipient address). According to actions/smtp/main.go, the Run method validates these fields before invoking mail.Send. Optional parameters include username, password, tls, and my-hostname for authenticated or TLS-encrypted connections.
How does the IMAP plugin handle TLS connections?
The IMAP plugin defaults to secure connections via imapclient.DialTLS as implemented in imap/client.go. Set tls: true (the default) and strict_host_check: true to enforce certificate validation against the hostname. For testing environments, set tls: false to use DialInsecure, though this is not recommended for production workflows handling sensitive data.
Can I access specific message headers from IMAP fetch results?
Yes. Use the dataitem parameter in fetch commands to specify exact header fields, such as BODY[HEADER.FIELDS (FROM TO SUBJECT DATE)]. The plugin's parseBodySection helper translates this syntax into go-imap structures. Results are stored under res.data.fetch.messages as a list, where each message contains the requested header fields as accessible properties (e.g., {{outputs.Check Inbox.data.fetch.messages[0].subject}}).
How do I verify that an SMTP message was actually delivered?
Configure a dependent job using the needs syntax to run an IMAP step after the SMTP step completes. In the IMAP step, search for the unique Message-ID or subject hash that mail/mail.go automatically appends via appendIDtoSubject. Assert that res.data.search.count is greater than zero to confirm the message arrived in the target mailbox.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →