hermes - ✅(Solved) Fix [Bug]: [Email] Audio attachments (.mp3/.wav/.m4a/.flac) fail to send — EmailAdapter lacks send_voice() [2 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
NousResearch/hermes-agent#24922Fetched 2026-05-14 03:50:34
View on GitHub
Comments
1
Participants
2
Timeline
7
Reactions
0
Author
Timeline (top)
labeled ×4cross-referenced ×2commented ×1

Error Message

The error message is None because the EmailAdapter does not override send_voice(), so it inherits the base class stub which returns NotImplementedError — but the actual exception is caught and only the error string (None) is logged.

  1. In ~/.hermes/logs/agent.log: Earlier in the session, before the routing was understood, the agent may also have logged:

Root Cause

1. should_send_media_as_audio() in gateway/platforms/base.py (lines 89–109)

_AUDIO_EXTS = frozenset({".ogg", ".opus", ".mp3", ".wav", ".m4a", ".flac"})

def should_send_media_as_audio(platform, ext: str, is_voice: bool = False) -> bool:
   normalized_ext = (ext or "").lower()
   if normalized_ext not in _AUDIO_EXTS:
       return False
   if _platform_name(platform) == "telegram":
       ...  # Telegram has special handling
   return True  # ← All non-Telegram platforms return True for audio exts

Since Email is not Telegram, any audio extension causes this function to return True, routing the file through send_voice().

2. EmailAdapter in gateway/platforms/email.py — missing send_voice()

EmailAdapter only implements 4 send methods:

  • send_typing()
  • send_image()
  • send_multiple_images()
  • send_document()

It does not implement send_voice(). When base.py calls EmailAdapter.send_voice(), the base class BasePlatformAdapter.send_voice() raises NotImplementedError, causing the silent failure.

3. File extension behavior

ExtensionIn _AUDIO_EXTS?RouteEmailAdapter methodResult
.mp3Yessend_voice()Not implementedFails
.wavYessend_voice()Not implementedFails
.m4aYessend_voice()Not implementedFails
.srtNosend_document()ImplementedWorks
.txtNosend_document()ImplementedWorks

Fix Action

Fixed

PR fix notes

PR #24931: fix(email): implement send_voice() to fix audio attachment delivery

Description (problem / solution / changelog)

Summary

Implements send_voice() in EmailAdapter to fix audio file attachments (.mp3, .wav, .m4a, .flac, .ogg, .opus) failing silently when sent via the Email platform.

Problem

When an audio file is sent through the Email gateway, should_send_media_as_audio() in base.py routes it to send_voice(). However, EmailAdapter does not implement send_voice(), so it falls back to the base class which just sends a text link (🔊 Audio: <path>) instead of attaching the file.

Fix

Added send_voice() to EmailAdapter that delegates to the existing send_document() method, ensuring audio files are delivered as proper email attachments with the correct filename.

Testing

  • All 81 email-related tests pass
  • Syntax validated via ast.parse()

Checklist

  • Changes are limited to gateway/platforms/email.py
  • No new dependencies
  • Follows existing adapter patterns (see other platform adapters like Discord, Slack)
  • Commit is signed

Fixes #24922

Changed files

  • gateway/platforms/email.py (modified, +21/-0)

PR #24932: fix(email): attach audio files sent as voice

Description (problem / solution / changelog)

Summary

  • implement EmailAdapter.send_voice() by delegating audio files to MIME document attachment delivery
  • add a regression test proving .mp3 voice/audio sends are attached instead of falling back to text-only path leakage

Why

The shared media router sends recognized audio extensions through send_voice() for non-Telegram platforms. Email has no native voice primitive, so it should preserve the generated audio as a normal email attachment.

Fixes #24922.

Tests

  • uv run pytest tests/gateway/test_email.py -q
  • uv run pytest tests/gateway/test_email.py::TestSendMethods::test_send_voice_attaches_audio_file tests/gateway/test_email.py::TestSendMethods::test_send_document_with_attachment tests/gateway/test_platform_base.py::TestShouldSendMediaAsAudio -q

Changed files

  • gateway/platforms/email.py (modified, +24/-0)
  • tests/gateway/test_email.py (modified, +38/-0)

Code Example

## Bug Description

Audio files (.mp3, .wav, .m4a, .flac, .ogg, .opus) sent via the Email platform fail silently. The gateway logs show:

---

The file never arrives as an email attachment. However, non-audio files like .srt or files renamed to .txt do arrive correctly as attachments.

## Root Cause

**1. `should_send_media_as_audio()` in `gateway/platforms/base.py` (lines 89109)**

---

Since Email is not Telegram, any audio extension causes this function to return True, routing the file through `send_voice()`.

**2. `EmailAdapter` in `gateway/platforms/email.py` — missing `send_voice()`**

`EmailAdapter` only implements 4 send methods:
- `send_typing()`
- `send_image()`
- `send_multiple_images()`
- `send_document()`

It does **not** implement `send_voice()`. When `base.py` calls `EmailAdapter.send_voice()`, the base class `BasePlatformAdapter.send_voice()` raises `NotImplementedError`, causing the silent failure.

**3. File extension behavior**

| Extension | In `_AUDIO_EXTS`? | Route | `EmailAdapter` method | Result |
|-----------|-------------------|-------|---------------------|--------|
| `.mp3`    | Yes               | `send_voice()` | **Not implemented** | Fails |
| `.wav`    | Yes               | `send_voice()` | **Not implemented** | Fails |
| `.m4a`    | Yes               | `send_voice()` | **Not implemented** | Fails |
| `.srt`    | No                | `send_document()` | Implemented | Works |
| `.txt`    | No                | `send_document()` | Implemented | Works |

## Proposed Fix

Implement `send_voice()` in `EmailAdapter` (`gateway/platforms/email.py`), delegating to `send_document()`:

---

## Labels

`bug` `platform/email`

### Steps to Reproduce


1. Connect the Email platform to Hermes (IMAP/SMTP configuration).
2. Ask Hermes to generate an audio file, e.g. via `mmx music generate`.
3. Ask Hermes to send the audio file via  in the reply.
4. Observe: the email arrives but the .mp3 file is **not** in the attachments.
5. Rename the same file to `.txt` and send again: the .txt file **does** arrive as an attachment.

### Expected Behavior

Audio files (.mp3, .wav, .m4a, .flac, .ogg, .opus) sent via  should arrive as email attachments.

## Actual Behavior

Audio files are silently dropped. The gateway logs show:

---

No attachment appears in the received email.

### Actual Behavior

Audio files are silently dropped with no visible error to the end user. What actually happens:

1. **In the email received by the user:** The audio file does not appear as an attachment. The body of the email may contain the text `🔊 Audio: /path/to/file.mp3` (rendered as plain text, not as a playable audio player or downloadable attachment), or it may contain no reference to the file at all.

2. **In `~/.hermes/logs/gateway.log`:** The following warning is logged for each failed audio file:

---

The error message is `None` because the `EmailAdapter` does not override `send_voice()`, so it inherits the base class stub which returns `NotImplementedError` — but the actual exception is caught and only the error string (`None`) is logged.

3. **In `~/.hermes/logs/agent.log`:** Earlier in the session, before the routing was understood, the agent may also have logged:

---

This is a different error (from `send_message` tool) that fires when trying to send a media-only message through the wrong delivery path — it is unrelated to the `send_voice()` issue above but compounds the confusion.

4. **File size of the received email:** The email is sent and received normally, but its size is smaller than expected because the audio file payload was never attached.

---

**Full error output from gateway.log:**

---

### Affected Component

Gateway (Telegram/Discord/Slack/WhatsApp)

### Messaging Platform (if gateway-related)

N/A (CLI only)

### Debug Report

---

### Operating System

Ubuntu 24.04

### Python Version

_No response_

### Hermes Version

_No response_

### Additional Logs / Traceback (optional)
RAW_BUFFERClick to expand / collapse

Bug Description

## Bug Description

Audio files (.mp3, .wav, .m4a, .flac, .ogg, .opus) sent via the Email platform fail silently. The gateway logs show:

[Email] Failed to send media (.mp3): None


The file never arrives as an email attachment. However, non-audio files like .srt or files renamed to .txt do arrive correctly as attachments.

## Root Cause

**1. `should_send_media_as_audio()` in `gateway/platforms/base.py` (lines 89–109)**

```python
_AUDIO_EXTS = frozenset({".ogg", ".opus", ".mp3", ".wav", ".m4a", ".flac"})

def should_send_media_as_audio(platform, ext: str, is_voice: bool = False) -> bool:
   normalized_ext = (ext or "").lower()
   if normalized_ext not in _AUDIO_EXTS:
       return False
   if _platform_name(platform) == "telegram":
       ...  # Telegram has special handling
   return True  # ← All non-Telegram platforms return True for audio exts

Since Email is not Telegram, any audio extension causes this function to return True, routing the file through send_voice().

2. EmailAdapter in gateway/platforms/email.py — missing send_voice()

EmailAdapter only implements 4 send methods:

  • send_typing()
  • send_image()
  • send_multiple_images()
  • send_document()

It does not implement send_voice(). When base.py calls EmailAdapter.send_voice(), the base class BasePlatformAdapter.send_voice() raises NotImplementedError, causing the silent failure.

3. File extension behavior

ExtensionIn _AUDIO_EXTS?RouteEmailAdapter methodResult
.mp3Yessend_voice()Not implementedFails
.wavYessend_voice()Not implementedFails
.m4aYessend_voice()Not implementedFails
.srtNosend_document()ImplementedWorks
.txtNosend_document()ImplementedWorks

Proposed Fix

Implement send_voice() in EmailAdapter (gateway/platforms/email.py), delegating to send_document():

async def send_voice(
   self,
   chat_id: str,
   audio_path: str,
   caption: Optional[str] = None,
   reply_to: Optional[str] = None,
   **kwargs,
) -> SendResult:
   """Send an audio file as an email attachment."""
   return await self.send_document(
       chat_id=chat_id,
       file_path=audio_path,
       caption=caption,
       **kwargs,
   )

Labels

bug platform/email

Steps to Reproduce

  1. Connect the Email platform to Hermes (IMAP/SMTP configuration).
  2. Ask Hermes to generate an audio file, e.g. via mmx music generate.
  3. Ask Hermes to send the audio file via in the reply.
  4. Observe: the email arrives but the .mp3 file is not in the attachments.
  5. Rename the same file to .txt and send again: the .txt file does arrive as an attachment.

Expected Behavior

Audio files (.mp3, .wav, .m4a, .flac, .ogg, .opus) sent via should arrive as email attachments.

Actual Behavior

Audio files are silently dropped. The gateway logs show:

[Email] Failed to send media (.mp3): None

No attachment appears in the received email.

Actual Behavior

Audio files are silently dropped with no visible error to the end user. What actually happens:

  1. In the email received by the user: The audio file does not appear as an attachment. The body of the email may contain the text 🔊 Audio: /path/to/file.mp3 (rendered as plain text, not as a playable audio player or downloadable attachment), or it may contain no reference to the file at all.

  2. In ~/.hermes/logs/gateway.log: The following warning is logged for each failed audio file:

[Email] Failed to send media (.mp3): None

The error message is None because the EmailAdapter does not override send_voice(), so it inherits the base class stub which returns NotImplementedError — but the actual exception is caught and only the error string (None) is logged.

  1. In ~/.hermes/logs/agent.log: Earlier in the session, before the routing was understood, the agent may also have logged:
WARNING [session_id] run_agent: Tool send_message returned error (0.10s): {"error": "send_message MEDIA delivery is currently only supported for telegram, discord, matrix, weixin, signal, yuanbao and feishu; target email had only media attachments"}

This is a different error (from send_message tool) that fires when trying to send a media-only message through the wrong delivery path — it is unrelated to the send_voice() issue above but compounds the confusion.

  1. File size of the received email: The email is sent and received normally, but its size is smaller than expected because the audio file payload was never attached.

Full error output from gateway.log:

WARNING gateway.platforms.base: [Email] Failed to send media (.mp3): None
WARNING gateway.platforms.base: [Email] Failed to send media (.wav): None
WARNING gateway.platforms.base: [Email] Failed to send media (.m4a): None

Affected Component

Gateway (Telegram/Discord/Slack/WhatsApp)

Messaging Platform (if gateway-related)

N/A (CLI only)

Debug Report

Above

Operating System

Ubuntu 24.04

Python Version

No response

Hermes Version

No response

Additional Logs / Traceback (optional)

Root Cause Analysis (optional)

No response

Proposed Fix (optional)

No response

Are you willing to submit a PR for this?

  • I'd like to fix this myself and submit a PR

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING