autoreg-skills-max: initial public release (restored, redacted, hardened)
This commit is contained in:
63
skills/email-infrastructure/references/html-otp-parsing.md
Normal file
63
skills/email-infrastructure/references/html-otp-parsing.md
Normal file
@@ -0,0 +1,63 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user