Skip to content

Martini Email Functions

Overview

Martini Email Functions gives you a set of functions for sending, reading, searching, and organizing email directly from your services and workflows. Every function handles its own connection lifecycle — you supply the server credentials, and Martini opens the connection, performs the operation, and closes it when done.

What You Will Learn

  • How to send new messages, replies, and forwarded messages with attachments
  • How to fetch, paginate, and search inbound messages from a mailbox
  • How to organize email by moving and deleting messages between IMAP folders

When To Use This

Use Martini Email Functions when you need to automate email-driven processes directly from a service or workflow — without writing low-level SMTP/IMAP session management code.

Common scenarios include:

  • Polling a shared inbox (e.g., invoices@company.com) and routing messages to downstream systems
  • Sending transactional notifications, order confirmations, or alerts from within a workflow
  • Replying to or forwarding emails as part of an approval or escalation process
  • Archiving processed messages into specific IMAP folders for audit purposes
  • Building paginated inbox views or search interfaces on top of a live mailbox

Prerequisites

Connecting to a Mail Server

Every email function shares a common set of connection input properties. Understanding them once means you can configure any function quickly — whether you are sending, reading, or organizing messages.

Mail Server Connection Properties

The table below covers every shared connection property. Set these consistently across all function calls in a single workflow to keep your credential management simple.

Property Example Value What It Controls
protocol imaps The transport protocol: smtp, smtps, imap, imaps, pop3, or pop3s
login invoices@company.com The mailbox account address used to authenticate
password app-specific-pw The account password or app-specific password; never a plain account password in prod
host imap.gmail.com The mail server hostname for the chosen protocol
port 993 The TCP port that pairs with the protocol (see reference table below)
debug false When true, prints the raw IMAP/POP3 session to the console for diagnostics

Supported Email Protocols and Ports

Choose the encrypted variant of each protocol in all production environments. Unencrypted protocols transmit credentials in plain text and should only be used in isolated local testing.

Protocol Port Use When
smtps 465 SMTP submission over implicit TLS
smtp 587 SMTP submission with STARTTLS (standard message submission port)
imaps 993 Reading and organizing mail over implicit TLS
imap 143 IMAP with STARTTLS upgrade or legacy unencrypted IMAP
pop3s 995 POP3 over implicit TLS
pop3 110 POP3 with STLS upgrade or legacy unencrypted POP3

Common Mail Server Hostnames

If you are unsure of your server's hostname, use these standard values for the major cloud mail providers.

Provider SMTP Host IMAP Host
Gmail / Google Workspace smtp.gmail.com imap.gmail.com
Outlook / Microsoft 365 smtp-mail.outlook.com imap-mail.outlook.com
Yahoo Mail smtp.mail.yahoo.com imap.mail.yahoo.com

Troubleshooting Mail Server Connection Issues

Problem Detection Cause Fix
Authentication rejected Function throws a login failure exception Invalid credentials, app password required, or provider blocked the sign-in Verify credentials and generate an app-specific password if required
Connection refused Function throws a connection refused exception Wrong host, wrong port, firewall restrictions, or service unavailable Verify hostname, protocol, port, and network connectivity
SSL handshake failure Function throws an SSL exception Certificate issues, TLS incompatibility, or protocol/port mismatch Verify certificates and ensure the protocol matches the expected TLS mode
debug output flooding logs Console fills with raw session data debug left enabled in production Set debug to false before deploying

Email Data Models Reference

Every email function uses one or more of the following data models. Understanding their properties helps you map data correctly in services and workflows.

Data Model Description
Message The central model returned when reading email. Holds to, cc, bcc, from, replyTo, subject, body, contentType, messageId, attachments, bodyParts, and headers.
Address Represents an RFC 822 email address. type identifies the address type; address holds the address string (e.g., vendor@example.com); personal holds the display name (e.g., Acme Supplies).
DataSource Represents a file attachment. When sending, populate name, contentType, and inputStream.
Header A name-value pair for a single MIME header. Use it to set custom headers on outgoing mail, for example X-Priority: 1 for high priority or X-Correlation-ID to carry a trace identifier across systems.
MailMetadata Returned after sending. The most useful properties are messageId (for correlating with later events), sentDate, from, recipients, subject, size, and headers.
PaginatedMessages Wraps the current page of Message data models together with totalCount (total messages in the folder) and totalPages (total pages at the requested limit).
DeleteEmailsResult Returned after deletion. Contains a messageIds array of the values that were successfully removed — use this to detect and log any IDs the server could not find.

Sending Email

The sending functions cover three scenarios:

  • Composing a new message from scratch (sendEmail)
  • Replying to an existing message with proper threading (replyToEmail)
  • Re-routing a message to new recipients (forwardEmail)

All three return a MailMetadata model describing the sent message.

Sending a New Message with sendEmail

Use sendEmail to compose and deliver a new message. CC, BCC, attachments, and custom headers are all optional.

Recipients: Pass one or more Address data models in the to property. Each Address has an address property (the email address) and a personal property (the display name).

Body format: Set isHtml to true when your body contains HTML markup; leave it false (the default) for plain text.

Attachments: Add a DataSource data model to the attachments list for each file. Set name to the attachment filename, contentType to the MIME type, and inputStream to the file bytes.

Example — sending an order confirmation with a PDF receipt:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// Build the recipient and attachment models
address {
    address  = customer@example.com
    personal = Jane Doe
}

dataSource {
    name        = order_1042_receipt.pdf
    contentType = application/pdf
    inputStream = <stream of packages/erp/output/order_1042_receipt.pdf>
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// Send the email
sendEmail(
    protocol:    'smtps',
    login:       'noreply@company.com',
    password:    smtpPassword,
    server:      'smtp.gmail.com',
    port:        465,
    from:        'noreply@company.com',
    to:          address,
    cc:          null,
    bcc:         null,
    subject:     'Your Order #1042 is Confirmed',
    isHtml:      true,
    body:        '<p>Hi Jane,</p><p>Your order has been confirmed. Please find your receipt attached.</p>',
    attachments: dataSource,
    headers:     null
)

Expected result: The function returns a MailMetadata model. The messageId property is most useful if you need to correlate the sent message with a later reply or audit log entry.

Replying to a Message with replyToEmail

Use replyToEmail when you already have a Message in hand — from readEmail, listEmails, or searchEmails — and want to send a threaded reply.

Threading: Automatically extracts the In-Reply-To and References headers from the original message so the reply lands in the correct conversation thread in any modern mail client. The subject is prefixed with Re: if it isn't already.

replyAll flag: Controls who receives the reply:

  • false (default) — reply goes only to the original sender
  • true — reply goes to all original TO, CC, and BCC recipients, useful for team inboxes

Example — acknowledging a vendor's invoice submission:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// `invoiceEmail` is a Message obtained earlier from searchEmails
replyToEmail(
    protocol:        'smtps',
    login:           'ap@company.com',
    password:        smtpPassword,
    host:            'smtp.gmail.com',
    port:            465,
    from:            'ap@company.com',
    originalMessage: invoiceEmail,
    replyAll:        false,
    isHtml:          false,
    body:            'Thank you — we have received your invoice and it is now under review. You can expect payment within 30 days.',
    attachments:     null,
    headers:         null
)

Expected result: The function returns a MailMetadata model describing the sent reply. The reply appears in the correct thread in the recipient's mail client.

Forwarding a Message with forwardEmail

Use forwardEmail to re-send an existing Message to a new set of recipients.

Original content: The original headers, body, and attachments are always preserved.

Additional content: Use additionalBody to prepend a note before the original content and additionalAttachments to append extra files. The isHtml flag applies only to additionalBody, not to the original body.

Example — escalating an unrecognized invoice to the finance manager:

1
2
3
4
5
// Build the recipient model
address {
    address  = finance-manager@company.com
    personal = Alex Finance
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// Forward the email with a note prepended
forwardEmail(
    protocol:              'smtps',
    login:                 'ap@company.com',
    password:              smtpPassword,
    host:                  'smtp.gmail.com',
    port:                  465,
    from:                  'ap@company.com',
    to:                    address,
    cc:                    null,
    bcc:                   null,
    originalMessage:       invoiceEmail,
    additionalBody:        'Alex — this invoice came from an unrecognized vendor and could not be matched to a PO. Please review.',
    isHtml:                false,
    additionalAttachments: null,
    headers:               null
)

Expected result: The function returns a MailMetadata model describing the forwarded message. The recipient sees the original message body below your prepended note.

Troubleshooting Sending Function Issues

Problem Detection Cause Fix
Empty recipient error Function throws on sendEmail to list is empty Add at least one Address model to to
Missing original message Function throws on replyToEmail originalMessage not provided Always pass the Message from a read function
Attachment not received Recipient sees email without attachment inputStream is null on the DataSource Ensure the file stream is open and non-null before calling sendEmail
HTML displayed as plain text Email body shows raw HTML tags isHtml left as false with an HTML body Set isHtml to true when body contains HTML markup

Reading Email

The reading functions give you three ways to access inbound messages, plus a utility for discovering what folders are available. Choose the function that matches your workflow pattern — polling for new messages, browsing all messages with pagination, or searching by specific criteria.

Fetching New Messages with readEmail

readEmail connects to your mail server and fetches messages.

IMAP: Returns only unread (UNSEEN) messages — making it ideal for polling workflows that process only what is new.

POP3: Returns all available messages because POP3 has no read/unread concept.

delete flag: Set to true to remove messages from the server immediately after fetching. This is a common pattern in fire-and-forget intake workflows where you want to ensure the same message is never processed twice.

Example — pulling new emails from a dedicated invoice inbox:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
readEmail(
    protocol: 'imaps',
    login:    'invoices@company.com',
    password: imapPassword,
    host:     'imap.gmail.com',
    port:     993,
    folder:   'INBOX',
    delete:   false,
    debug:    false
)

Expected result: Returns a messages array of Message models, each carrying the sender, recipients, subject, body, attachments, and headers. Hold on to the messageId on each Message — you will pass it to replyToEmail, moveEmails, or deleteEmails later in the same workflow.

Browsing Messages with Pagination using listEmails

listEmails returns all messages in a folder regardless of read status.

Pagination: Supports limit and offset for page-by-page access, making it well suited for inbox review interfaces, audit logs, or any workflow that needs to walk a folder incrementally. Set limit to 0 to fetch all messages at once.

Example — building a paginated inbox view (page 2, 20 messages per page):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
listEmails(
    protocol: 'imaps',
    login:    'support@company.com',
    password: imapPassword,
    host:     'imap.gmail.com',
    port:     993,
    folder:   'INBOX',
    limit:    20,
    offset:   20,
    debug:    false
)

Expected result: Returns a PaginatedMessages model containing messages (the current page), totalCount (total messages in the folder), and totalPages (total pages at the chosen limit).

Finding Specific Messages with searchEmails

searchEmails filters messages server-side rather than pulling the entire mailbox into memory.

Filters: All filters are optional — only the ones you provide are applied. When multiple filters are set, all conditions must be satisfied (AND logic).

IMAP only: POP3 has no server-side search capability. This function requires imap or imaps.

Available search filters:

Filter Type Description
fromAddress String Match messages from this exact sender address
subject String Match messages containing this substring in subject
since Date Match messages received on or after this date
before Date Match messages received before this date
unreadOnly Boolean When true, only return unread (UNSEEN) messages

Example — finding all unread invoices from a specific vendor received this month:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
searchEmails(
    protocol:    'imaps',
    login:       'invoices@company.com',
    password:    imapPassword,
    host:        'imap.gmail.com',
    port:        993,
    folder:      'INBOX',
    fromAddress: 'billing@acme-supplies.com',
    subject:     'Invoice',
    since:       Date.parse('yyyy-MM-dd', '2025-06-01'),
    before:      null,
    unreadOnly:  true,
    debug:       false
)

Expected result: Returns a messages array of Message models matching all provided filters.

Discovering Available Folders with listFolders

listFolders returns all folder names visible to the authenticated IMAP account.

Usage: Use the returned strings directly as the folder property value in readEmail, listEmails, searchEmails, moveEmails, and deleteEmails.

When to call it: Call listFolders at the start of any workflow that moves or archives messages — this confirms destination folders exist before you attempt to use them.

Example — confirming destination folders exist before processing:

1
2
3
4
5
6
7
8
listFolders(
    protocol: 'imaps',
    login:    'invoices@company.com',
    password: imapPassword,
    host:     'imap.gmail.com',
    port:     993,
    debug:    false
)

Expected result: Returns a plain list of folder name strings (e.g., INBOX, Processed, Escalated). Check this list to confirm your expected folders are present before the rest of the workflow runs.

Troubleshooting Reading Function Issues

Problem Detection Cause Fix
No messages returned by readEmail Empty messages array No unread messages in the folder Check the mailbox directly; IMAP only returns UNSEEN messages
searchEmails returns no results Empty messages array Filters too restrictive Test with fewer filters to confirm messages exist
listFolders not available Function throws unsupported operation POP3 server used instead of IMAP Switch to imap or imaps — POP3 does not support folders
Pagination returns wrong page Unexpected messages in result offset calculated incorrectly Calculate offset as (pageNumber - 1) * limit

Organizing Email

Once messages are read and processed, use the organizing functions to keep the mailbox clean and structured. moveEmails organizes messages into categorized folders; deleteEmails permanently removes messages you no longer need. Both functions identify messages by messageId and work exclusively on IMAP servers.

Moving Messages Between Folders with moveEmails

moveEmails transfers one or more messages from a source folder to a destination folder on the same IMAP server. All matched messages are moved in a single server operation.

Identifying messages: Messages are identified by their messageId values — the ones returned by any read function.

Example — archiving processed invoices out of INBOX:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
moveEmails(
    protocol:          'imaps',
    login:             'invoices@company.com',
    password:          imapPassword,
    host:              'imap.gmail.com',
    port:              993,
    sourceFolder:      'INBOX',
    destinationFolder: 'Processed',
    messageIds:        [ '<invoice-001@acme.com>', '<invoice-002@acme.com>' ],
    debug:             false
)

Expected result: Returns a list of messageId strings that were successfully moved. Any ID absent from the result was not found in sourceFolder.

Deleting Messages with deleteEmails

deleteEmails permanently removes messages from an IMAP folder by messageId.

When to use: Use deleteEmails when archiving is not required and you want to keep the mailbox clean. For audit-trail requirements, prefer moveEmails to an archive folder instead.

Example — purging spam-classified messages from a monitored inbox:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
deleteEmails(
    protocol:   'imaps',
    login:      'support@company.com',
    password:   imapPassword,
    host:       'imap.gmail.com',
    port:       993,
    folder:     'INBOX',
    messageIds: [ '<spam-001@unknown.com>', '<spam-002@unknown.com>' ],
    debug:      false
)

Expected result: Returns a DeleteEmailsResult model whose messageIds array lists every ID that was successfully removed. IDs absent from that list were not found in the specified folder.

Troubleshooting Organizing Function Issues

Problem Detection Cause Fix
moveEmails returns empty list No IDs in result Messages not found in sourceFolder Confirm message IDs with listEmails or searchEmails; verify source folder name via listFolders
Destination folder not found Server-side error on move Folder does not exist on the server Call listFolders first to confirm the destination folder exists
deleteEmails permanently removes wrong messages Unintended messages removed Incorrect messageId values passed Double-check messageId values from the read function before passing to deleteEmails
Organize functions unavailable Function throws unsupported operation Using POP3 instead of IMAP Switch to imap or imaps — folder operations require IMAP

Helpful Resources