Files
autoreg-skills-max/skills/email-infrastructure/references/html-otp-parsing.md

64 lines
2.2 KiB
Markdown

# HTML OTP Parsing Notes
Use this when IMAP fetch succeeds but naive regex extraction returns the wrong verification code.
## Problem pattern
Some transactional emails contain multiple `\d{6}` candidates in one message because the HTML includes:
- the visible OTP block,
- responsive/mobile duplicate markup,
- unrelated build/tracking numbers embedded in template fragments.
If you do `re.findall(r'\\b\\d{6}\\b', body)[0]`, you may grab a stale or irrelevant number.
## Preferred extraction order
1. **Subject line first** if it explicitly contains the OTP.
2. **OTP-specific markup** next:
- `<strong>123456</strong>`
- `.otp-code`
- monospace / headline blocks near words like `verification code`, `验证码`, `OTP`, `code`
3. **Generic body regex** only as fallback.
4. If multiple distinct codes remain, prefer the one from the **latest message** that appears in OTP-specific markup, not the first raw body match.
## Minimal robust pattern
```python
from email.header import decode_header
import email as em
import re
def decode_subject(msg):
parts = []
for value, enc in decode_header(msg.get('Subject', '')):
if isinstance(value, bytes):
parts.append(value.decode(enc or 'utf-8', errors='replace'))
else:
parts.append(value)
return ''.join(parts)
def extract_code(subject, body):
# 1) explicit subject code
m = re.search(r'\b(\d{4,8})\b', subject)
if m:
return m.group(1)
# 2) OTP-specific HTML / text blocks
patterns = [
r'otp-code[^>]*>\s*(\d{4,8})\s*<',
r'<strong[^>]*>\s*(\d{4,8})\s*</strong>',
r'(?:verification code|验证码|OTP|code)[^\d]{0,40}(\d{4,8})',
]
for pat in patterns:
m = re.search(pat, body, re.I | re.S)
if m:
return m.group(1)
# 3) generic fallback
codes = re.findall(r'\b(\d{4,8})\b', body)
codes = [c for c in codes if not (2020 <= int(c) <= 2035)]
return codes[0] if codes else None
```
## Session-derived example shape
Observed shape: one provider email produced several six-digit matches from a single HTML message. The visible OTP and the first regex hit did not reliably align. The safe fix was to stop trusting `codes[0]` and rank candidates by subject / OTP markup / latest message.