{"repo":"NousResearch/hermes-agent","public_id":"15160","display_label":"Adding missing Date header to outbound emails","summary":"Multiple fixes and a bug report addressing the absence of a required Date header in outbound emails, which caused messages to be bounced by mail filters. Several parallel or iterative PRs target different code paths where the header was missing.","subsystem":null,"counts":{"members":5,"open_issues":0,"open_issues_distinct":0,"open_prs":0,"closed_issues":1,"merged_prs":2,"attempt_prs":2},"landed_fix":{"status":"merged_to_main","basis":"structural","pr":16568},"resolution":{"state":"resolved","by":"pr-16568"},"freshness":{"state":"verified","last_verified_at":"2026-05-04T09:48:21+00:00","is_stale":false},"grouping":{"backbone":"STRUCTURAL_SPANNING","link_density":0.4},"fix_edges":[{"issue_number":15160,"pr_number":16568,"tier":"verified","basis":"closing_ref","confidence":0.95,"recoverable_from_timeline":true},{"issue_number":15160,"pr_number":19646,"tier":"verified","basis":"closing_ref","confidence":0.95,"recoverable_from_timeline":true},{"issue_number":15197,"pr_number":19646,"tier":"verified","basis":"closing_ref","confidence":0.95,"recoverable_from_timeline":true}],"members":[{"kind":"issue","number":15160,"title":"[Bug]: Outbound Hermes emails missing Date header — bounced by mail filter","url":null,"state":"closed"},{"kind":"pr","number":15164,"title":"fix(email): add required Date header to outbound mail","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#16568","number":16568},{"kind":"pr","value":"#15160","number":15160}],"category":"merged_via","implication":"superseded"},"merged":false},{"kind":"pr","number":15230,"title":"fix(email): add Date header to send_message_tool._send_email (closes #15160)","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#16568","number":16568},{"kind":"pr","value":"#15160","number":15160},{"kind":"pr","value":"#15164","number":15164}],"category":"superseded_by_pr","implication":"superseded"},"merged":false},{"kind":"pr","number":16568,"title":"fix(email): add required Date header to outbound mail (salvage #15164)","url":null,"state":"merged","close_reason":{"category":"merged","implication":"superseded"},"merged":true,"is_fix_pr":true,"fix_tier":"verified","files_changed":["gateway/platforms/email.py","scripts/release.py","tests/gateway/test_email.py","tools/send_message_tool.py"],"fix_hunks":[{"file":"gateway/platforms/email.py","hunks":["@@ -28,6 +28,7 @@\n from email.mime.multipart import MIMEMultipart\n from email.mime.text import MIMEText\n from email.mime.base import MIMEBase\n+from email.utils import formatdate\n from email import encoders\n from pathlib import Path\n from typing import Any, Dict, List, Optional","@@ -504,6 +505,7 @@ def _send_email(\n             msg[\"In-Reply-To\"] = original_msg_id\n             msg[\"References\"] = original_msg_id\n \n+        msg[\"Date\"] = formatdate(localtime=True)\n         msg_id = f\"<hermes-{uuid.uuid4().hex[:12]}@{self._address.split('@')[1]}>\"\n         msg[\"Message-ID\"] = msg_id\n ","@@ -586,6 +588,7 @@ def _send_email_with_attachment(\n             msg[\"In-Reply-To\"] = original_msg_id\n             msg[\"References\"] = original_msg_id\n \n+        msg[\"Date\"] = formatdate(localtime=True)\n         msg_id = f\"<hermes-{uuid.uuid4().hex[:12]}@{self._address.split('@')[1]}>\"\n         msg[\"Message-ID\"] = msg_id\n "]},{"file":"scripts/release.py","hunks":["@@ -53,6 +53,7 @@\n     \"[redacted:email]\": \"say8hi\",\n     \"[redacted:email]\": \"web3blind\",\n     \"[redacted:email]\": \"alexg0bot\",\n+    \"[redacted:email]\": \"scheidti\",\n     \"[redacted:email]\": \"benjaminsehl\",\n     \"[redacted:email]\": \"Nerijusas\",\n     \"[redacted:email]\": \"Ito-69\","]},{"file":"tests/gateway/test_email.py","hunks":["@@ -488,6 +488,7 @@ def test_reply_uses_re_prefix(self):\n             self.assertEqual(send_call[\"Subject\"], \"Re: Project question\")\n             self.assertEqual(send_call[\"In-Reply-To\"], \"<[redacted:email]>\")\n             self.assertEqual(send_call[\"References\"], \"<[redacted:email]>\")\n+            self.assertIn(\"Date\", send_call)\n \n     def test_reply_does_not_double_re(self):\n         \"\"\"If subject already has Re:, don't add another.\"\"\"","@@ -519,6 +520,7 @@ def test_no_thread_context_uses_default_subject(self):\n \n             send_call = mock_server.send_message.call_args[0][0]\n             self.assertEqual(send_call[\"Subject\"], \"Re: Hermes Agent\")\n+            self.assertIn(\"Date\", send_call)\n \n \n class TestSendMethods(unittest.TestCase):","@@ -889,6 +891,11 @@ def test_send_email_tool_success(self):\n             self.assertEqual(result[\"platform\"], \"email\")\n             _, kwargs = mock_server.starttls.call_args\n             self.assertIsInstance(kwargs[\"context\"], ssl.SSLContext)\n+            send_call = mock_server.send_message.call_args[0][0]\n+            self.assertEqual(send_call[\"Subject\"], \"Hermes Agent\")\n+            self.assertIn(\"Date\", send_call)\n+            self.assertEqual(send_call[\"To\"], \"[redacted:email]\")\n+            self.assertEqual(send_call[\"From\"], \"[redacted:email]\")\n \n     @patch.dict(os.environ, {\n         \"EMAIL_ADDRESS\": \"[redacted:email]\","]},{"file":"tools/send_message_tool.py","hunks":["@@ -1075,6 +1075,7 @@ async def _send_email(extra, chat_id, message):\n     \"\"\"Send via SMTP (one-shot, no persistent connection needed).\"\"\"\n     import smtplib\n     from email.mime.text import MIMEText\n+    from email.utils import formatdate\n \n     address = extra.get(\"address\") or os.getenv(\"EMAIL_ADDRESS\", \"\")\n     password = [redacted:secret-assignment]\"EMAIL_PASSWORD\", \"\")","@@ -1092,6 +1093,7 @@ async def _send_email(extra, chat_id, message):\n         msg[\"From\"] = address\n         msg[\"To\"] = chat_id\n         msg[\"Subject\"] = \"Hermes Agent\"\n+        msg[\"Date\"] = formatdate(localtime=True)\n \n         server = smtplib.SMTP(smtp_host, smtp_port)\n         server.starttls(context=ssl.create_default_context())\n"]}]},{"kind":"pr","number":19646,"title":"fix(cli,email): quoted-relative file-drop paths + Date header on tool email path","url":null,"state":"merged","close_reason":{"category":"merged","implication":"superseded"},"merged":true,"is_fix_pr":true,"fix_tier":"verified","files_changed":["cli.py","tools/send_message_tool.py"],"fix_hunks":[{"file":"cli.py","hunks":["@@ -1505,6 +1505,10 @@ def _detect_file_drop(user_input: str) -> \"dict | None\":\n         or stripped.startswith('\"~')\n         or stripped.startswith(\"'/\")\n         or stripped.startswith(\"'~\")\n+        or stripped.startswith('\"./')\n+        or stripped.startswith('\"../')\n+        or stripped.startswith(\"'./\")\n+        or stripped.startswith(\"'../\")\n         or (len(stripped) >= 4 and stripped[0] in (\"'\", '\"') and stripped[2] == \":\" and stripped[3] in (\"\\\\\", \"/\") and stripped[1].isalpha())\n     )\n     if not starts_like_path:"]},{"file":"tools/send_message_tool.py","hunks":["@@ -10,9 +10,10 @@\n import logging\n import os\n import re\n-from typing import Dict, Optional\n import ssl\n import time\n+from email.utils import formatdate\n+from typing import Dict, Optional\n \n from agent.redact import redact_sensitive_text\n \n"]}]}],"trust":{"default_tier":"verified","includes_suggested":false}}