51 lines
1.8 KiB
Python
51 lines
1.8 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Read Apodex OTP from Gmail IMAP via app password.
|
|
Usage: python read_otp_gmail.py
|
|
Waits up to 90s for unseen Apodex email, prints OTP code.
|
|
"""
|
|
import imaplib, ssl, re, email as eml, time, sys
|
|
|
|
GMAIL = "[REDACTED-NAME]@gmail.com"
|
|
APP_PASS = "IMAP_APP_PASSWORD"
|
|
|
|
def read_otp(timeout=90):
|
|
ctx = ssl.create_default_context()
|
|
deadline = time.time() + timeout
|
|
while time.time() < deadline:
|
|
try:
|
|
mail = imaplib.IMAP4_SSL("imap.gmail.com", 993, ssl_context=ctx, timeout=15)
|
|
mail.login(GMAIL, APP_PASS)
|
|
mail.select("INBOX")
|
|
_, msgs = mail.search(None, '(FROM "apodex" UNSEEN)')
|
|
if msgs[0]:
|
|
mid = msgs[0].split()[-1]
|
|
_, data = mail.fetch(mid, "(RFC822)")
|
|
raw = data[0][1].decode("utf-8", errors="ignore")
|
|
msg = eml.message_from_string(raw)
|
|
body = ""
|
|
if msg.is_multipart():
|
|
for part in msg.walk():
|
|
if part.get_content_type() == "text/plain":
|
|
body = part.get_payload(decode=True).decode("utf-8", errors="ignore")
|
|
break
|
|
else:
|
|
body = msg.get_payload(decode=True).decode("utf-8", errors="ignore")
|
|
codes = re.findall(r"\b\d{6}\b", body)
|
|
mail.store(mid, "+FLAGS", "\\Seen")
|
|
mail.logout()
|
|
if codes:
|
|
return codes[0]
|
|
mail.logout()
|
|
except Exception as e:
|
|
print(f" IMAP retry: {e}", file=sys.stderr)
|
|
time.sleep(5)
|
|
return None
|
|
|
|
if __name__ == "__main__":
|
|
otp = read_otp(timeout=90)
|
|
if otp:
|
|
print(f"OTP: {otp}")
|
|
else:
|
|
print("No OTP found")
|