96 lines
3.7 KiB
Python
96 lines
3.7 KiB
Python
import os
|
|
import datetime
|
|
import mimetypes
|
|
import time
|
|
from imap_tools import MailBox, AND
|
|
from sqlalchemy.orm import Session
|
|
from database import SessionLocal, Email, Attachment
|
|
from dotenv import load_dotenv
|
|
|
|
load_dotenv()
|
|
|
|
MAIL_SERVER = os.getenv("MAIL_SERVER")
|
|
MAIL_USERNAME = os.getenv("MAIL_USERNAME")
|
|
MAIL_PASSWORD = os.getenv("MAIL_PASSWORD")
|
|
MAIL_PORT = int(os.getenv("MAIL_PORT", 993))
|
|
|
|
def fetch_and_store_emails():
|
|
"""
|
|
Connects to Gmail, fetches UNREAD emails, stores them in DB, and marks as READ.
|
|
"""
|
|
print(f"[{datetime.datetime.now()}] Checking for new emails...")
|
|
|
|
if not MAIL_USERNAME or not MAIL_PASSWORD or MAIL_USERNAME == "your-email@gmail.com":
|
|
print("Skipping Email Sync: Credentials not configured.")
|
|
return {"status": "skipped", "message": "Credentials not configured"}
|
|
|
|
db: Session = SessionLocal()
|
|
count = 0
|
|
|
|
try:
|
|
# Connect to Inbox
|
|
# imap-tools MailBox defaults to SSL (port 993) if not specified, but we make it explicit here.
|
|
with MailBox(MAIL_SERVER, port=MAIL_PORT).login(MAIL_USERNAME, MAIL_PASSWORD, initial_folder='INBOX') as mailbox:
|
|
# Fetch UNREAD emails
|
|
for msg in mailbox.fetch(AND(seen=False)):
|
|
print(f"Processing Email: {msg.subject}")
|
|
|
|
# Check if already exists (optional, but good practice if marking read fails)
|
|
# For now using simplistic approach: if we fetch it, we save it.
|
|
|
|
new_email = Email(
|
|
subject=msg.subject,
|
|
sender=msg.from_,
|
|
body=msg.text or msg.html,
|
|
received_date=msg.date,
|
|
is_read=False # Consumed by app, but 'seen' on server
|
|
)
|
|
db.add(new_email)
|
|
db.commit() # Commit to get ID
|
|
db.refresh(new_email)
|
|
|
|
|
|
# Process Attachments
|
|
for i, att in enumerate(msg.attachments):
|
|
filename = att.filename
|
|
if not filename:
|
|
# Fallback for missing filename
|
|
ext = mimetypes.guess_extension(att.content_type) or ".bin"
|
|
timestamp = int(time.time())
|
|
filename = f"attachment_{timestamp}_{i}{ext}"
|
|
|
|
print(f" - Attachment: {filename}")
|
|
new_attachment = Attachment(
|
|
email_id=new_email.id,
|
|
filename=filename,
|
|
content_type=att.content_type,
|
|
file_content=att.payload # raw bytes
|
|
)
|
|
db.add(new_attachment)
|
|
|
|
db.commit()
|
|
|
|
# Mark as Read on Server (Auto-done by fetch unless bulk=True or mark_seen=False)
|
|
# imap-tools fetches are auto-seen by default.
|
|
count += 1
|
|
|
|
print(f"Sync Complete. {count} new emails.")
|
|
return {"status": "success", "count": count}
|
|
|
|
except Exception as e:
|
|
error_msg = str(e)
|
|
print(f"Error fetching emails: {error_msg}")
|
|
|
|
if "AUTHENTICATIONFAILED" in error_msg or "Invalid credentials" in error_msg:
|
|
return {
|
|
"status": "error",
|
|
"message": f"Authentication Failed: {error_msg}. \n[HINT]: If using Gmail, you MUST use an 'App Password', not your login password. Also ensure IMAP is enabled in Gmail Settings."
|
|
}
|
|
|
|
return {"status": "error", "message": error_msg}
|
|
finally:
|
|
db.close()
|
|
|
|
if __name__ == "__main__":
|
|
fetch_and_store_emails()
|