odysseus-dev/odysseus · error · Error

Unsubscribe failed

Error message

Unsubscribe failed

What it means

Thrown when POST of the unsubscribe request (method_index 0 = reply-based List-Unsubscribe) returns success=false. The button re-enables and restores its method label, and the toast shows the server's error or the generic 'Unsubscribe failed'.

Source

Thrown at static/js/emailLibrary.js:1759

        btn.disabled = true;
        btn.textContent = 'Sending…';
        try {
          const r = await fetch(emailApiUrl('/api/email/unsubscribe/execute', {
            account_id: state._libAccountId || undefined,
          }), {
            method: 'POST',
            credentials: 'same-origin',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
              uid: c.uid,
              folder: c.folder || state._libFolder || 'INBOX',
              account_id: state._libAccountId || '',
              method_index: 0,
              move_to_spam: false,
            }),
          });
          const d = await r.json().catch(() => ({}));
          if (!d.success) throw new Error(d.error || 'Unsubscribe failed');
          btn.textContent = 'Sent';
          _markUnsubscribeCardDone(modal, idx);
          showToast('Unsubscribe email sent');
          _showUnsubscribeCleanupPrompt(modal, [c]);
        } catch (err) {
          console.error(err);
          btn.disabled = false;
          btn.textContent = _unsubscribeMethodLabel(c.recommended_method);
          showToast(err?.message || 'Unsubscribe failed');
        }
      });
    });
  } catch (err) {
    console.error(err);
    finishScanStatus?.('Failed to scan email headers');
  }
}

View on GitHub (pinned to f9235ebbf1)

Solutions

  1. Read d.error in the response body (Network tab) — it names whether parsing or sending failed
  2. Verify the account has working outgoing/SMTP credentials
  3. Use the cleanup fallback (mark as spam / delete) when the sender's unsubscribe flow is broken
  4. Refresh the list and retry if the UID was stale
Defensive patterns

Strategy: fallback

Validate before calling

if (!c.list_unsubscribe && !c.recommended_method) { showToast('No unsubscribe method available — use mark-as-spam'); return; }

Try / catch

try { const d = await r.json().catch(() => ({})); if (!d.success) throw new Error(d.error || 'Unsubscribe failed'); ... } catch (err) { btn.disabled = false; btn.textContent = _unsubscribeMethodLabel(c.recommended_method); showToast(err?.message || 'Unsubscribe failed'); }

Prevention

When it happens

Trigger: Clicking Send on an unsubscribe card: the message's List-Unsubscribe mailto can't be parsed or sent (missing/invalid header, SMTP relay refuses the sender), the UID/folder pair no longer resolves, or the account's outgoing credentials are missing.

Common situations: mailto unsubscribe address missing from the header; provider blocks programmatic sends to that address; message moved/expunged so uid lookup fails; account configured for receive-only without SMTP.

Related errors


AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14). Data as JSON: /api/errors/c54b6725ccc740a9. Report an issue: GitHub.