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:

  1. Validate that the with map contains required parameters (SMTP requires addr, from, to; IMAP requires host, username, password).
  2. Log truncated input using probe.TruncateMapStringAny for security.
  3. Create callbacks via mail.WithBefore/WithAfter or imap.WithBefore/WithAfter to hook into lifecycle events.
  4. Delegate protocol work to library code—SMTP calls mail.Send from mail/mail.go, while IMAP calls imap.Request from imap/client.go.
  5. Return a map[string]any that 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: Dial establishes 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 MessageCount to issue MAIL FROM, RCPT TO, and DATA commands.
  • Enrichment: Each message receives a unique Message-ID via genMsgID, and subjects automatically append a hash ID through appendIDtoSubject.

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:

  1. Dial: Uses imapclient.DialTLS or imapclient.DialInsecure based on configuration.
  2. Authenticate: Login with the provided Username and Password.
  3. Execute: The ExecCommands dispatcher runs each command from the workflow (e.g., Select, Search, Fetch).

Helper methods translate workflow syntax into go-imap structures:

  • parseSequenceSet handles message sequences.
  • parseUIDSet manages UID ranges.
  • parseFetchItems and parseBodySection convert expressions like BODY[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.
  • username and password: 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:

  • host and port: Server endpoint (defaults to 993 with TLS).
  • username and password: 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 like since, flags, or text.
  • fetch: Retrieves message data; sequence specifies ID ranges (* for all), and dataitem defines 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.go and actions/imap/main.go.
  • SMTP configuration requires addr, from, and to parameters in the with block, delegating transmission logic to mail.Send in mail/mail.go.
  • IMAP configuration requires host, username, and password, executing commands through imap.Request in imap/client.go using the emersion/go-imap/v2 library.
  • Both plugins return map[string]any results 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →