Added all

This commit is contained in:
Guillem Hernandez Sola
2026-04-07 19:37:59 +02:00
commit da6dabcc62
42 changed files with 1959 additions and 0 deletions

43
outlook/email_login.py Normal file
View File

@@ -0,0 +1,43 @@
import imaplib
# ==========================================
# 1. CONFIGURATION
# ==========================================
EMAIL_ADDRESS = "marti@agile611.com"
# ⚠️ Insert your generated App Password here (no spaces)
PASSWORD = "fcztyfdwpfrgqjgl" # Replace with your actual App Password
IMAP_SERVER = "outlook.office365.com"
IMAP_PORT = 993
def test_app_password_login():
print(f"🔌 Connecting to {IMAP_SERVER} on port {IMAP_PORT}...")
try:
# Connect to the server using SSL/TLS encryption
mail = imaplib.IMAP4_SSL(IMAP_SERVER, IMAP_PORT)
# Attempt plaintext login using the App Password
print("🔐 Attempting login with App Password...")
mail.login(EMAIL_ADDRESS, PASSWORD)
print("✅ Success! The App Password worked perfectly.")
# Select the inbox to verify we can read data
status, messages = mail.select("INBOX")
if status == "OK":
message_count = messages[0].decode('utf-8')
print(f"📥 INBOX selected successfully. Total messages: {message_count}")
# Safely log out
mail.logout()
print("👋 Logged out successfully.")
except imaplib.IMAP4.error as e:
print("\n❌ Login failed!")
print(f"Error details: {e}")
print("\n⚠️ Note: If you see 'BasicAuthBlocked' again, your organization's global Azure settings have completely disabled basic authentication, overriding the App Password.")
if __name__ == "__main__":
test_app_password_login()

177
outlook/get_token.py Normal file
View File

@@ -0,0 +1,177 @@
import msal
import imaplib
import os
import csv
import re
import time
import socket
# 🚨 Force Python to drop the connection if Microsoft stops responding (tarpitting)
socket.setdefaulttimeout(30)
# ==========================================
# 1. CONFIGURATION
# ==========================================
CLIENT_ID = "05332268-8149-449f-a1f8-1efadd17166f"
EMAIL_ADDRESS = "guillem@agile611.com"
AUTHORITY = "https://login.microsoftonline.com/884a3c53-8a5a-4d79-b0e0-a62ab5a794a1"
# MSAL automatically requests offline_access, so we only list the IMAP scope here
SCOPES = ["https://outlook.office.com/IMAP.AccessAsUser.All"]
# ==========================================
# 2. HELPER FUNCTION: GENERATE CSV
# ==========================================
def generate_user_csv(email_address, first_name="Guillem", last_name="Hernandez Sola"):
username = email_address.split("@")[0]
headers = [
"originUsername", "targetUsername", "password", "pop3enabled",
"pop3password", "aliases", "forwards", "filters",
"forename", "surname", "mailboxStatus"
]
row_data = {
"originUsername": username, "targetUsername": username,
"password": "TempWebmailPassword123!", "pop3enabled": "true",
"pop3password": "", "aliases": "", "forwards": "", "filters": "",
"forename": first_name, "surname": last_name, "mailboxStatus": "premium"
}
csv_filename = f"{username}_import.csv"
with open(csv_filename, mode="w", newline="", encoding="utf-8") as file:
writer = csv.DictWriter(file, fieldnames=headers, delimiter=";")
writer.writeheader()
writer.writerow(row_data)
print(f"📝 Migration CSV generated: {csv_filename}")
# ==========================================
# 3. TOKEN & CONNECTION MANAGERS
# ==========================================
def get_valid_token(app):
"""Checks the cache for a valid token, refreshes silently if needed, or prompts user."""
accounts = app.get_accounts()
if accounts:
result = app.acquire_token_silent(SCOPES, account=accounts[0])
if result and "access_token" in result:
return result["access_token"]
flow = app.initiate_device_flow(scopes=SCOPES)
if "user_code" not in flow:
raise ValueError("Failed to create device flow. Check your Client ID and Azure settings.")
print("\n🚨 ACTION REQUIRED 🚨")
print(flow["message"])
print("⏳ Waiting for browser authentication...")
result = app.acquire_token_by_device_flow(flow)
if "access_token" not in result:
raise Exception(f"Failed to get token: {result.get('error_description')}")
return result["access_token"]
def connect_to_imap(email, token):
"""Creates a fresh, authenticated connection to the IMAP server."""
auth_string = f"user={email}\x01auth=Bearer {token}\x01\x01"
mail = imaplib.IMAP4_SSL("outlook.office365.com", 993)
mail.authenticate("XOAUTH2", lambda x: auth_string.encode("utf-8"))
return mail
# ==========================================
# 4. MAIN EXECUTION
# ==========================================
def main():
print("🔄 Initializing Microsoft Authentication...")
app = msal.PublicClientApplication(CLIENT_ID, authority=AUTHORITY)
try:
access_token = get_valid_token(app)
print("\n✅ Access Token Acquired Successfully!")
print("\n🔌 Connecting to Outlook IMAP server...")
mail = connect_to_imap(EMAIL_ADDRESS, access_token)
print("✅ Successfully logged into IMAP via OAuth2!")
except Exception as e:
print(f"\n❌ Authentication failed: {e}")
return
try:
username = EMAIL_ADDRESS.split("@")[0]
base_download_dir = f"downloaded_emails_{username}"
os.makedirs(base_download_dir, exist_ok=True)
status, folders = mail.list()
if status == "OK":
print(f"📂 Found {len(folders)} folders. Starting full account backup...\n")
for folder_data in folders:
folder_string = folder_data.decode('utf-8')
if "\\Noselect" in folder_string:
continue
match = re.search(r'\"([^\"]+)\"$', folder_string)
folder_name = match.group(1) if match else folder_string.split()[-1].strip('"')
print(f"📁 Scanning folder: {folder_name}")
status, _ = mail.select(f'"{folder_name}"', readonly=True)
if status != "OK":
print(f" ⚠️ Could not open {folder_name}. Skipping.")
continue
status, data = mail.search(None, "ALL")
email_ids = data[0].split()
if not email_ids:
print(" ↳ Folder is empty.")
continue
print(f" ↳ Found {len(email_ids)} emails. Downloading...")
safe_folder_name = "".join([c for c in folder_name if c.isalnum() or c in (' ', '-', '_')]).strip()
folder_dir = os.path.join(base_download_dir, safe_folder_name)
os.makedirs(folder_dir, exist_ok=True)
# Download loop with Reconnect & Timeout Logic
for e_id in email_ids:
file_path = os.path.join(folder_dir, f"email_{e_id.decode('utf-8')}.eml")
# 🚀 SKIP EXISTING: Don't re-download emails we already have!
if os.path.exists(file_path):
continue
success = False
while not success:
try:
status, msg_data = mail.fetch(e_id, "(RFC822)")
for response_part in msg_data:
if isinstance(response_part, tuple):
raw_email = response_part[1]
with open(file_path, "wb") as f:
f.write(raw_email)
success = True
# Catch token expiration, forced disconnects, AND silent timeouts
except (imaplib.IMAP4.abort, imaplib.IMAP4.error, ConnectionResetError, socket.timeout, TimeoutError) as e:
print(f"\n ⚠️ Connection lost or timed out. Refreshing token and reconnecting...")
try:
access_token = get_valid_token(app)
mail = connect_to_imap(EMAIL_ADDRESS, access_token)
mail.select(f'"{folder_name}"', readonly=True)
print(" ✅ Reconnected! Resuming download...")
except Exception as reconnect_error:
print(f" ❌ Reconnection failed: {reconnect_error}. Retrying in 5 seconds...")
time.sleep(5)
print(f"\n🎉 All folders successfully downloaded to '{base_download_dir}'!")
mail.logout()
print("👋 Logged out successfully.\n")
print("⚙️ Generating configuration files...")
generate_user_csv(EMAIL_ADDRESS)
print("🎉 Migration prep complete!")
except Exception as e:
print(f"\n❌ A critical error occurred: {e}")
if __name__ == "__main__":
main()

142
outlook/marti.py Normal file
View File

@@ -0,0 +1,142 @@
import msal
import imaplib
import os
import csv
import re # Added for parsing folder names safely
# ==========================================
# 1. CONFIGURATION
# ==========================================
CLIENT_ID = "05332268-8149-449f-a1f8-1efadd17166f"
EMAIL_ADDRESS = "marti@agile611.com"
AUTHORITY = "https://login.microsoftonline.com/884a3c53-8a5a-4d79-b0e0-a62ab5a794a1"
SCOPES = ["https://outlook.office.com/IMAP.AccessAsUser.All"]
# ==========================================
# 2. HELPER FUNCTION: GENERATE CSV
# ==========================================
def generate_user_csv(email_address, first_name="Marti", last_name="Montfort Ruiz"):
username = email_address.split("@")[0]
headers = [
"originUsername", "targetUsername", "password", "pop3enabled",
"pop3password", "aliases", "forwards", "filters",
"forename", "surname", "mailboxStatus"
]
row_data = {
"originUsername": username, "targetUsername": username,
"password": "TempWebmailPassword123!", "pop3enabled": "true",
"pop3password": "", "aliases": "", "forwards": "", "filters": "",
"forename": first_name, "surname": last_name, "mailboxStatus": "premium"
}
csv_filename = f"{username}_import.csv"
with open(csv_filename, mode="w", newline="", encoding="utf-8") as file:
writer = csv.DictWriter(file, fieldnames=headers, delimiter=";")
writer.writeheader()
writer.writerow(row_data)
print(f"📝 Migration CSV generated: {csv_filename}")
def main():
# ==========================================
# 3. GETTING THE OAUTH2 TOKEN
# ==========================================
print("🔄 Initializing Microsoft Authentication...")
app = msal.PublicClientApplication(CLIENT_ID, authority=AUTHORITY)
flow = app.initiate_device_flow(scopes=SCOPES)
if "user_code" not in flow:
raise ValueError("Failed to create device flow. Check your Client ID and Azure settings.")
print("\n🚨 ACTION REQUIRED 🚨")
print(flow["message"])
print("\n⏳ Waiting for browser authentication...")
result = app.acquire_token_by_device_flow(flow)
if "access_token" not in result:
print("\n❌ Failed to get token:", result.get("error_description"))
return
access_token = result["access_token"]
print("\n✅ Access Token Acquired Successfully!")
# ==========================================
# 4. CONNECTING TO IMAP & DOWNLOADING ALL FOLDERS
# ==========================================
print("\n🔌 Connecting to Outlook IMAP server...")
auth_string = f"user={EMAIL_ADDRESS}\x01auth=Bearer {access_token}\x01\x01"
try:
mail = imaplib.IMAP4_SSL("outlook.office365.com", 993)
mail.authenticate("XOAUTH2", lambda x: auth_string.encode("utf-8"))
print("✅ Successfully logged into IMAP via OAuth2!")
# Base directory for this user
username = EMAIL_ADDRESS.split("@")[0]
base_download_dir = f"downloaded_emails_{username}"
os.makedirs(base_download_dir, exist_ok=True)
# Fetch all folders in the mailbox
status, folders = mail.list()
if status == "OK":
print(f"📂 Found {len(folders)} folders. Starting full account backup...\n")
for folder_data in folders:
folder_string = folder_data.decode('utf-8')
# Skip unselectable folders (like root directory markers)
if "\\Noselect" in folder_string:
continue
# Safely extract the folder name (handles spaces and quotes)
match = re.search(r'\"([^\"]+)\"$', folder_string)
folder_name = match.group(1) if match else folder_string.split()[-1].strip('"')
print(f"📁 Scanning folder: {folder_name}")
# Select the folder (readonly to prevent accidental modifications)
status, _ = mail.select(f'"{folder_name}"', readonly=True)
if status != "OK":
print(f" ⚠️ Could not open {folder_name}. Skipping.")
continue
status, data = mail.search(None, "ALL")
email_ids = data[0].split()
if not email_ids:
print(" ↳ Folder is empty.")
continue
print(f" ↳ Found {len(email_ids)} emails. Downloading...")
# Create a safe subfolder name for the OS
safe_folder_name = "".join([c for c in folder_name if c.isalnum() or c in (' ', '-', '_')]).strip()
folder_dir = os.path.join(base_download_dir, safe_folder_name)
os.makedirs(folder_dir, exist_ok=True)
# Download each email into its respective folder
for e_id in email_ids:
status, msg_data = mail.fetch(e_id, "(RFC822)")
for response_part in msg_data:
if isinstance(response_part, tuple):
raw_email = response_part[1]
file_path = os.path.join(folder_dir, f"email_{e_id.decode('utf-8')}.eml")
with open(file_path, "wb") as f:
f.write(raw_email)
print(f"\n🎉 All folders successfully downloaded to '{base_download_dir}'!")
mail.logout()
print("👋 Logged out successfully.\n")
# ==========================================
# 5. GENERATE THE CSV
# ==========================================
print("⚙️ Generating configuration files...")
generate_user_csv(EMAIL_ADDRESS)
print("🎉 Migration prep complete!")
except imaplib.IMAP4.error as e:
print(f"\n❌ IMAP Authentication failed: {e}")
if __name__ == "__main__":
main()