PDA

View Full Version : [Python] Neopets Account Activation Email Client



Squirtle
01-26-2024, 06:33 AM
This is a small class I wanted to share, designed for use on my personal mail server. I opted for IMAP over SMTP, so I haven't tested it with typical email providers like Gmail, Outlook, etc.

The purpose of this class is to automatically retrieve the activation code from a Neopets email, thereby streamlining the account activation process when used with an account creator. Once it secures the activation code, the corresponding email is deleted from the server, keeping the inbox clean.


import imaplib
import email
import time
from typing import Optional


class EmailClient:
def __init__(self) -> None:
self.email_address = "<EMAIL_ADDRESS>"
self.password = "<PASSWORD>"
self.mail_server = "<IMAP_SERVER>"
self.mail = imaplib.IMAP4_SSL(self.mail_server)

def login_to_account(self) -> None:
"""Logs into the email account."""
try:
self.mail.login(self.email_address, self.password)
except imaplib.IMAP4.error as e:
raise Exception(f"Failed to login: {e}")

def find_email(self, subject: str = "Welcome and Account", timeout: int = 300) -> Optional[str]:
"""
Searches and processes the email with the specified subject.

Args:
subject (str): The subject of the email to search for.
timeout (int): The time in seconds to keep searching before giving up.

Returns:
Optional[str]: The extracted activation code, or None if not found.
"""
self.mail.select("inbox", readonly=False)
end_time = time.time() + timeout

while time.time() < end_time:
typ, data = self.mail.search(None, f"(SUBJECT \"{subject}\")")
if data[0]:
activation_code = self.process_emails(data)
if activation_code:
return activation_code
time.sleep(5)

return None

def process_emails(self, data: str) -> Optional[str]:
"""Processes emails to find the one with the given subject and extracts the activation code."""
if not data[0].decode():
return None

for num in data[0].split():
typ, data = self.mail.fetch(num, "(RFC822)")
msg = email.message_from_bytes(data[0][1])
activation_code = self.extract_activation_code(msg)
if activation_code:
self.mail.store(num, '+FLAGS', '\\Deleted')
return activation_code
return None

def extract_activation_code(self, msg) -> Optional[str]:
"""Extracts the activation code from the email message."""
message = msg.get_payload(decode=True).decode('utf-8')
return self.get_substring_between_text(message, "box: ", ")")

def cleanup_mailbox(self) -> None:
"""Cleans up the mailbox by expunging deleted emails and logging out."""
self.mail.expunge()
self.mail.logout()

def get_activation_code(self) -> Optional[str]:
"""Main method to log in to the account and find the activation email."""
self.login_to_account()
activation_code = self.find_email()
self.cleanup_mailbox()
return activation_code

def get_substring_between_text(self, text: str, start: str, end: str) -> str:
"""
Extracts a substring from the provided text, located between specified start and end strings.

Args:
text (str): The text to search within.
start (str): The start delimiter of the substring.
end (str): The end delimiter of the substring.

Returns:
str: The extracted substring. Returns an empty string if delimiters are not found.
"""
try:
return text.split(start, 1)[1].split(end, 1)[0]
except IndexError:
return ""

Praise_the_Sun
01-26-2024, 07:48 AM
Looks cool. Thanks for sharing :)