Hermes Email++
Hermes Email++ is a third-party IMAP/SMTP platform adapter for Hermes Agent.
It is registered as email_pp, independently of Hermes' built-in email
platform. It routes each RFC email thread to its own Hermes session, sends
plain-text and HTML email, and supports a review-draft workflow for common
inline forwards.
Installation And Enablement
Install this package into the same Python environment as a supported Hermes Agent 0.19 release:
$ python -m pip install hermes-email-pp
$ hermes plugins enable email-pp
Pip-installed plugins are discovered through the hermes_agent.plugins entry
point. Enabling email-pp explicitly permits this third-party code to load.
Restart the gateway after installing or changing configuration. hermes plugins list shows discovery and enablement, and hermes gateway status shows the
registered and connected platforms.
Put the credentials in the active Hermes profile's ~/.hermes/.env (or the
profile-specific equivalent):
EMAIL_PP_ADDRESS=agent@example.com
EMAIL_PP_PASSWORD=an-app-password
EMAIL_PP_IMAP_HOST=imap.example.com
EMAIL_PP_SMTP_HOST=smtp.example.com
EMAIL_PP_ALLOWED_USERS=operator@example.com
EMAIL_PP_REQUIRE_AUTHENTICATED_SENDER=true
All four required variables must be non-empty before environment-driven
configuration enables Email++. The EMAIL_PP_* namespace is deliberately
isolated: built-in EMAIL_* credentials are never read.
Enable the Email++ gateway platform in ~/.hermes/config.yaml when it is not
auto-enabled from the complete required environment configuration:
gateway:
platforms:
email_pp:
enabled: true
For a mailbox shared with the built-in adapter, use only one adapter. Keep
the EMAIL_* credentials absent and disable email in the gateway
configuration before enabling Email++ with its EMAIL_PP_* credentials. Two
adapters polling the same mailbox can race, duplicate processing, or send
conflicting replies.
Settings
Environment variables take precedence over matching extra values in the
Email++ platform configuration.
| Setting | Required | Default | Meaning |
|---|---|---|---|
EMAIL_PP_ADDRESS |
Yes | - | Agent mailbox address and SMTP envelope identity. |
EMAIL_PP_PASSWORD |
Yes | - | IMAP/SMTP password or provider-issued app password. |
EMAIL_PP_IMAP_HOST |
Yes | - | IMAP server hostname. |
EMAIL_PP_SMTP_HOST |
Yes | - | SMTP server hostname. |
EMAIL_PP_IMAP_PORT |
No | 993 |
IMAP-over-TLS port. |
EMAIL_PP_SMTP_PORT |
No | 587 |
SMTP STARTTLS port; use 465 for implicit TLS. |
EMAIL_PP_POLL_INTERVAL |
No | 15 |
Inbox polling interval in seconds; values below one second are treated as one second. |
EMAIL_PP_MAILBOX |
No | INBOX |
Mailbox selected for polling. |
EMAIL_PP_ALLOWED_USERS |
No | empty | Comma-separated sender-address allowlist. Required unless EMAIL_PP_ALLOW_ALL_USERS is enabled. |
EMAIL_PP_ALLOW_ALL_USERS |
No | false |
Accept every non-automated sender. This also bypasses sender-authentication checks; do not use for an Internet-facing mailbox. |
EMAIL_PP_REQUIRE_AUTHENTICATED_SENDER |
No | true |
Require a passing DMARC result in Authentication-Results for allowlisted senders. |
EMAIL_PP_AUTHSERV_ID |
No | empty | Optional authentication-service identifier that must prefix the trusted Authentication-Results header. |
EMAIL_PP_QUOTE_MODE |
No | always |
always quotes the source email, forwarded quotes only parsed forwards, and never omits visible quotes. |
Email Behavior
Ordinary Replies
Each RFC thread is mapped to a private Hermes thread. Message-ID,
References, and In-Reply-To preserve continuity across replies and gateway
restarts. Replies include both text/plain and safe text/html alternatives.
The selected quote mode controls whether the original content is visibly
quoted; normal replies retain RFC In-Reply-To and References headers.
The adapter rejects automated mail, self-mail, malformed message-ID headers, senders outside the allowlist, and (by default) messages without a passing DMARC result. It only sends when Hermes supplies a known sender and reply route, preventing arbitrary outbound email addresses from being used as a delivery target.
Forwarded Review Drafts
Email++ recognizes English inline forwards in these forms:
---------- Forwarded message ---------
-----Original Message-----
Use a short task prompt before the boundary, followed by a complete forwarded
message with at least From, Subject, and a non-empty body. The first Hermes
response is sent to the forwarder as a separate email with subject
Draft: Re: <original subject>; it does not reply to the original
correspondent and has no original-thread reply headers. The visible quote
contains only the original message, never the wrapper task prompt. A reply to
that draft stays in the same Hermes session and is sent as a normal revision.
Only English Gmail and Outlook inline forwards matching the boundaries above are supported. Attachments-as-forwards, localized client formatting, nested or ambiguous forwards, and forwards without the required headers/body are not parsed. A suspected forward that cannot be parsed receives a safe notice and creates no draft or agent task. This fail-closed behavior prevents wrapper text or untrusted forwarded content from being mistaken for an instruction.
Security And Data Handling
- Use a dedicated mailbox and a least-privilege provider app password, not a primary account password. Restrict IMAP/SMTP access to TLS-enabled endpoints.
- Store secrets in the Hermes profile
.envwith owner-only filesystem permissions or use the deployment platform's secret store. Never commit the.envfile or app password. - Use a small, explicit
EMAIL_PP_ALLOWED_USERSlist. LeaveEMAIL_PP_ALLOW_ALL_USERSunset, and keep authenticated-sender verification enabled. SetEMAIL_PP_AUTHSERV_IDwhen the receiving infrastructure has a known authentication-results service. - Treat sender authentication as a mailbox-side defense, not proof that email content is trustworthy. Forwarded message bodies are reference data and are explicitly separated from the authorized task prompt.
- Inbound attachments are written to temporary files and exposed to Hermes as media URLs; the adapter does not scan, size-limit, or delete them itself. Apply mailbox-provider malware controls, restrict tool access for the Email++ platform, and clean the host temporary directory according to local policy.
- Thread routing, delivery details, quote sources, and draft context are kept
locally at
~/.hermes/email_pp/threads.json(or the activeHERMES_HOME). The directory is mode0700and the state file is mode0600, but it is not encrypted. It is bounded to 500 threads and a 90-day retention period; back up or purge it according to the mailbox's data-retention policy.
Limitations
The adapter polls one IMAP mailbox and supports IMAP-over-TLS plus SMTP STARTTLS or implicit SMTP TLS. It does not provide mailbox synchronization, server-side draft storage, attachment malware scanning, arbitrary outbound mail, non-English forward parsing, or direct delivery to an original forwarded-message sender.
Development Validation
Run the complete release checks from a clean checkout:
$ uv run ruff check .
$ uv run ruff format --check .
$ uv run mypy hermes_email_pp
$ uv run pytest --cov=hermes_email_pp tests/
$ uv build --out-dir dist --clear
The release smoke test installs the built wheel with a supported Hermes Agent
0.19 release, then confirms the email-pp entry point loads without replacing
the built-in email registration.
Releases
- Update
[project].versioninpyproject.tomland add the matching version section toCHANGELOG.md. - Commit and merge the release changes, then create and push a tag matching
vX.Y.Z. The tag must equalvfollowed by[project].version, for example package version0.2.0requires tagv0.2.0. - The Release workflow runs the full validation suite, builds the wheel and source distribution, publishes those exact artifacts to PyPI, and creates a GitHub Release with generated notes and the same artifacts. A failure at any stage prevents later stages from running.
The workflow has a manual workflow_dispatch tag input for recovering a valid
existing tag; it applies the same tag and version validation.
Before the first release, create a protected GitHub Actions environment named
pypi and configure PyPI Trusted Publishing for project hermes-email-pp with
GitHub owner JNevrly, repository hermes_email_pp, workflow
.github/workflows/release.yml (workflow filename release.yml), and
environment pypi. PyPI supports creating this as a pending publisher before
the project exists. No PyPI API token or repository secret is needed.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file hermes_email_pp-0.1.1.tar.gz.
File metadata
- Download URL: hermes_email_pp-0.1.1.tar.gz
- Upload date:
- Size: 17.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bd96c0589c6308442cd7dc3ce3376a69cd8a6b380bd178e79eae4cd89267fde2
|
|
| MD5 |
bfddc35a80b88aa801a82f46bbac4149
|
|
| BLAKE2b-256 |
a51718dc6dd428631c2216f17425f775c0ba9b9ed01d576c507bec61bc4199df
|
Provenance
The following attestation bundles were made for hermes_email_pp-0.1.1.tar.gz:
Publisher:
release.yml on JNevrly/hermes_email_pp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hermes_email_pp-0.1.1.tar.gz -
Subject digest:
bd96c0589c6308442cd7dc3ce3376a69cd8a6b380bd178e79eae4cd89267fde2 - Sigstore transparency entry: 2583177330
- Sigstore integration time:
-
Permalink:
JNevrly/hermes_email_pp@c124be6c374e175dfe5672c3b8845d8fd537f851 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/JNevrly
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@c124be6c374e175dfe5672c3b8845d8fd537f851 -
Trigger Event:
push
-
Statement type:
File details
Details for the file hermes_email_pp-0.1.1-py3-none-any.whl.
File metadata
- Download URL: hermes_email_pp-0.1.1-py3-none-any.whl
- Upload date:
- Size: 20.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
59dd26f54aceae6286a6f9d4c9846137cfef35d749e21fcd73105fff46581a8f
|
|
| MD5 |
a4a575c29597c35827d6fdff1997a752
|
|
| BLAKE2b-256 |
8b892541ad848658306dbdcf25a655fe57a8be295d598aec7550cccdeb78615c
|
Provenance
The following attestation bundles were made for hermes_email_pp-0.1.1-py3-none-any.whl:
Publisher:
release.yml on JNevrly/hermes_email_pp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hermes_email_pp-0.1.1-py3-none-any.whl -
Subject digest:
59dd26f54aceae6286a6f9d4c9846137cfef35d749e21fcd73105fff46581a8f - Sigstore transparency entry: 2583177340
- Sigstore integration time:
-
Permalink:
JNevrly/hermes_email_pp@c124be6c374e175dfe5672c3b8845d8fd537f851 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/JNevrly
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@c124be6c374e175dfe5672c3b8845d8fd537f851 -
Trigger Event:
push
-
Statement type: