odysseus-dev/odysseus · warning · Error
Cannot create reply: sender address is missing from this ema
Error message
Cannot create reply: sender address is missing from this email.
What it means
A local validation throw, not a network error: when building a reply/reply-all draft, the computed To address (from the original message's sender) is empty or whitespace, so the draft would have no recipient. Forward mode is exempt because the user supplies recipients.
Source
Thrown at static/js/emailInbox.js:929
toAddress = originalToWithoutMe.join(', ') || originalCcWithoutMe[0] || data.from_address;
ccAddresses = originalCcWithoutMe.filter(addr => !originalToWithoutMe.some(t => extractEmail(t) === extractEmail(addr))).join(', ');
} else {
// Build reply-all: TO = original sender, CC = everyone else (To + Cc minus me)
ccAddresses = buildReplyAllCc(data, myAddresses);
}
} else if (mode === 'forward') {
toAddress = '';
subjectPrefix = 'Fwd: ';
}
// Don't double-prefix `Re:` / `Fwd:` when the subject already starts with one.
// Replies to replies were producing `Re: Re: Re: …` which can also break
// some IMAP servers' header parsing on very long subject lines.
let _baseSubject = (data.subject || '').trim();
if (subjectPrefix === 'Re: ' && /^re\s*:/i.test(_baseSubject)) subjectPrefix = '';
else if (subjectPrefix === 'Fwd: ' && /^fwd?\s*:/i.test(_baseSubject)) subjectPrefix = '';
if (mode !== 'forward' && !String(toAddress || '').trim()) {
throw new Error('Cannot create reply: sender address is missing from this email.');
}
let content = `To: ${toAddress}\nSubject: ${subjectPrefix}${_baseSubject}`;
if (ccAddresses) content += `\nCc: ${ccAddresses}`;
if (mode !== 'forward' && data.message_id) content += `\nIn-Reply-To: ${data.message_id}`;
if (mode !== 'forward' && data.message_id) content += `\nReferences: ${data.references ? data.references + ' ' + data.message_id : data.message_id}`;
content += `\nX-Source-UID: ${em.uid}`;
content += `\nX-Source-Folder: ${folderAtStart}`;
if (data.attachments && data.attachments.length > 0) {
const attStr = data.attachments.map(a => `${a.index}:${a.filename}:${a.size}`).join('|');
content += `\nX-Attachments: ${attStr}`;
if (mode === 'forward') content += `\nX-Forward-Attachments: 1`;
}
content += '\n---\n';
// Format the original date in a human-readable way for the quote header
let niceDate = data.date || '';
try {
if (data.date) {View on GitHub (pinned to f9235ebbf1)
Solutions
- Open the raw message source and check what the From header actually contains
- For such messages, use Forward instead and type the recipient manually
- If you own the parser, ensure sender extraction falls back to Reply-To then From
- Improve the UX by pre-filling the compose window with an empty To instead of throwing, letting the user fill it
Example fix
// before
if (mode !== 'forward' && !String(toAddress || '').trim()) {
throw new Error('Cannot create reply: sender address is missing from this email.');
}
// after — open compose with empty To instead of failing
if (mode !== 'forward' && !String(toAddress || '').trim()) {
toAddress = '';
uiModule.showToast('No sender address found — enter a recipient');
} Defensive patterns
Strategy: validation
Validate before calling
const senderAddr = String(toAddress || '').trim();
if (mode !== 'forward' && !senderAddr) { openComposeWith({ to: '', subject: `${subjectPrefix}${_baseSubject}`, warn: 'No sender address on original — add a recipient' }); return; } Type guard
function hasRoutableSender(data) { const v = String(data?.from_address || data?.sender || '').trim(); return /^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(v); } Try / catch
try { if (mode !== 'forward' && !hasRoutableSender(data)) throw new Error('Cannot create reply: sender address is missing from this email.'); ... } catch (e) { uiModule.showError(e.message); } Prevention
- Extract sender via fallback chain: Reply-To → From → Sender before giving up
- Offer Forward as the automatic alternative when sender is unparseable
- Log the raw From header when extraction fails to improve the parser
When it happens
Trigger: Clicking Reply/Reply-All on a message whose From header lacks a routable address — e.g. 'Undisclosed recipients', a malformed From with only a display name, or parser output that produced no email address. Only mode !== 'forward' path throws.
Common situations: Automated/noreply mailers with non-standard headers; a provider-specific header layout the parser does not extract sender from; corrupted message metadata in the fetched JSON.
Related errors
- Email account not found for selector {account!r}. Available
- IMAP folder not found: {folder}
- Invalid draft payload: {exc}
- Invalid send payload: {exc}
- d && d.detail ? d.detail : ('HTTP ' + res.status)
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/c27efa9f69eda8a1.
Report an issue: GitHub.