diff --git a/broker_sync/providers/imap.py b/broker_sync/providers/imap.py index e935bab..9d52478 100644 --- a/broker_sync/providers/imap.py +++ b/broker_sync/providers/imap.py @@ -163,7 +163,11 @@ def fetch_activities(creds: ImapCreds) -> list[Activity]: if sender in _IE_SENDERS or sender.endswith("@investengine.com"): out.extend(ie_parser.parse_invest_engine_email(raw)) ie_parsed += 1 - elif sender in _SCHWAB_SENDERS or sender.endswith("@schwab.com"): + elif ( + sender in _SCHWAB_SENDERS + or sender.endswith("@schwab.com") + or sender.endswith(".schwab.com") # e.g. donotreply@mail.schwab.com + ): html = _html_or_text(msg) out.extend(parse_schwab_email(html)) schwab_parsed += 1 diff --git a/tests/providers/test_imap.py b/tests/providers/test_imap.py index 63638cb..9c1fe8d 100644 --- a/tests/providers/test_imap.py +++ b/tests/providers/test_imap.py @@ -99,3 +99,18 @@ def test_non_ie_activities_passed_through_unchanged() -> None: routed = _split_ie_by_isa_cap([schwab_act]) assert routed[0].account_id == "schwab-workplace" assert routed[0].account_type is AccountType.GIA + + +def test_schwab_subdomain_sender_matches() -> None: + """Real Schwab trade emails come from `donotreply@mail.schwab.com` + (subdomain), not just `donotreply@schwab.com`. The matcher must + accept either form.""" + from broker_sync.providers.imap import _SCHWAB_SENDERS + # Verify the static set works + assert "donotreply@schwab.com" in _SCHWAB_SENDERS + # Verify the subdomain suffix check + for addr in ( + "donotreply@mail.schwab.com", + "wealthnotify@equityawards.schwab.com", + ): + assert addr.endswith(".schwab.com"), addr