Skip to content

feat(email): HTML rendering for attachment send paths - #54073

Closed
swissly wants to merge 1 commit into
NousResearch:mainfrom
swissly:feat/email-html-all-paths
Closed

feat(email): HTML rendering for attachment send paths#54073
swissly wants to merge 1 commit into
NousResearch:mainfrom
swissly:feat/email-html-all-paths

Conversation

@swissly

@swissly swissly commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Summary

Add HTML email rendering to the 2 send paths that were missing it: _send_email_with_attachment and _send_email_with_attachments.

Previously, only _send_email (plain replies) supported multipart/alternative with HTML. The attachment paths sent plain text only, so emails with file attachments never got rich formatting.

Changes

  • plugins/platforms/email/adapter.py:
    • Add _attach_body() — attach plain+HTML to a message
    • Add _create_body_part() — create multipart/alternative body for use inside multipart/mixed
    • Add _attach_parts() — shared helper: plain text always, HTML when html_format: true
    • Modify _send_email_with_attachment: use _create_body_part(body) instead of bare MIMEText
    • Modify _send_email_with_attachments: same

Supersedes

Closes #46619 (which targeted the old gateway/platforms/email.py path before the plugin migration).

Refs: #11941

Add _attach_body, _create_body_part, _attach_parts helper methods to
EmailAdapter so multipart/alternative HTML emails work on all 3 send
paths (_send_email, _send_email_with_attachment, _send_email_with_attachments).

Previously only _send_email supported HTML. The attachment paths sent
plain text only.

Supersedes NousResearch#46619 (which targeted the old gateway/platforms/email.py path).

Refs: NousResearch#11941
Copilot AI review requested due to automatic review settings June 28, 2026 08:18
@swissly

swissly commented Jun 28, 2026

Copy link
Copy Markdown
Contributor Author

Closing: checklist review found scope violations (bundled unrelated openviking change + duplicated HTML logic). Reopening clean PR.

@swissly swissly closed this Jun 28, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds HTML email rendering/styling support to the email platform adapter’s outbound send paths (including attachment sends) so recipients can see rich formatting via multipart/alternative rather than plain text only. Also introduces an OpenViking viking_add_resource cost warning when adding a full GitHub repository URL.

Changes:

  • Add HTML wrapper + inline-style injection and an html_format config flag to enable/disable HTML email bodies.
  • Wrap attachment send bodies in multipart/alternative for proper plain+HTML behavior inside multipart/mixed.
  • Add GitHub repo-root URL detection + cost warnings to the OpenViking add-resource tool schema/response.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
plugins/platforms/email/adapter.py Adds HTML email rendering/styling helpers and updates send paths to include optional HTML parts.
plugins/memory/openviking/init.py Adds GitHub repo URL detection and emits cost warnings when queueing full-repo resources.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +981 to +997
if self._html_format:
try:
import markdown
html_body = markdown.markdown(
body, extensions=["tables", "fenced_code", "nl2br"]
)
html_body = _style_html_email(_HTML_PREFIX + html_body + _HERMES_EMAIL_FOOTER)
msg.attach(MIMEText(body, "plain", "utf-8"))
msg.attach(MIMEText(html_body, "html", "utf-8"))
except ImportError:
logger.debug("[Email] markdown not installed, sending plain text")
msg.attach(MIMEText(body, "plain", "utf-8"))
except Exception as e:
logger.warning("[Email] HTML conversion failed, falling back to plain: %s", e)
msg.attach(MIMEText(body, "plain", "utf-8"))
else:
msg.attach(MIMEText(body, "plain", "utf-8"))
Comment on lines +516 to +528
def _is_github_repo_url(url: str) -> bool:
"""Check if URL is a GitHub repo root (not a specific file/blob/tree)."""
from urllib.parse import urlparse
parsed = urlparse(url)
if not parsed.hostname or not parsed.hostname.endswith("github.com"):
return False
parts = [p for p in parsed.path.strip("/").split("/") if p]
# github.com/owner/repo — exactly 2 path segments, no /blob/ or /tree/
if len(parts) != 2:
return False
# Normalize .git suffix (owner/repo.git → owner/repo)
repo = parts[1].removesuffix(".git")
return bool(repo)
# email:
# skip_attachments: true
self._skip_attachments = extra.get("skip_attachments", False)
self._html_format = extra.get("html_format", True)
Comment on lines 531 to 535
ADD_RESOURCE_SCHEMA = {
"name": "viking_add_resource",
"description": (
"Add a remote URL or local file/directory to the OpenViking knowledge base. "
"Remote resources must be public http(s), git, or ssh URLs. "
@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/plugins Plugin system and bundled plugins platform/email Email (IMAP/SMTP) adapter labels Jun 28, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Related: supersedes closed #46619 (which targeted the pre-migration gateway/platforms/email.py path), and overlaps the open email-HTML cluster #25441 / #36853 plus feature spec #11941. Note: this PR also bundles an unrelated change to plugins/memory/openviking/__init__.py (adds _is_github_repo_url detection) that is out of scope for email HTML rendering — worth isolating before review.

swissly added a commit to swissly/hermes-agent that referenced this pull request Jul 3, 2026
Add HTML email rendering to _send_email_with_attachment and
_send_email_with_attachments. Previously only _send_email supported
multipart/alternative with HTML; attachment paths sent plain text only.

- Add _attach_body/_create_body_part/_attach_parts helpers
- Add _style_html_email with inline CSS for Gmail/Outlook compat
- Add _HTML_PREFIX/_HERMES_EMAIL_FOOTER HTML wrapper templates
- Add html_format config option (default: true, opt-out: false)
- Both attachment paths now use _create_body_part for HTML support
- _send_email uses _attach_body (consolidated, no duplicated logic)

Lazy markdown import — adapter works without markdown installed.
Graceful fallback: conversion failure → plain text + warning.

Supersedes NousResearch#46619 (old gateway path) and NousResearch#54073 (bundled scope).
Refs: NousResearch#11941, NousResearch#36853
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have platform/email Email (IMAP/SMTP) adapter type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants