""" VWP BEC Incident - Send phishing notification to all affected recipients. Sends from JR's account via Microsoft Graph API sendMail endpoint. """ import json import subprocess import sys import tempfile import os # === Configuration === TENANT_ID = "5c53ae9f-7071-4248-b834-8685b646450f" APP_ID = "fabb3421-8b34-484b-bc17-e46de9703418" APP_SECRET = "~QJ8Q~NyQSs4OcGqHZyPrA2CVnq9KBfKiimntbMO" JR_USER_ID = "0af923d0-48c5-4cc1-8553-c60625802815" JR_EMAIL = "j-r@valleywideplastering.com" RECIPIENTS_FILE = r"D:\ClaudeTools\temp\vwp_exchange_recipients.json" # Addresses to exclude (lowercase for comparison) EXCLUDE_EXACT = { "j-r@valleywideplastering.com", "jr@valleywideplastering.com", "jr@casarica.net", "jrsuperwall@gmail.com", "kathya@azappliancehome.com.com", # malformed double .com } EXCLUDE_DOMAINS = ["bidmail.com", "onmicrosoft.com"] def get_access_token(): """Acquire OAuth2 token via client credentials flow.""" token_url = f"https://login.microsoftonline.com/{TENANT_ID}/oauth2/v2.0/token" result = subprocess.run( [ "curl", "-s", "-X", "POST", token_url, "-H", "Content-Type: application/x-www-form-urlencoded", "-d", f"client_id={APP_ID}&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default&client_secret={APP_SECRET}&grant_type=client_credentials", ], capture_output=True, text=True ) resp = json.loads(result.stdout) if "access_token" not in resp: print("[ERROR] Failed to get access token:") print(json.dumps(resp, indent=2)) sys.exit(1) print("[OK] Access token acquired") return resp["access_token"] def load_recipients(): """Load and filter recipients from the JSON file.""" with open(RECIPIENTS_FILE, encoding="utf-8") as f: data = json.load(f) raw = data["all_unique_recipients"] print(f"[INFO] Raw recipient count: {len(raw)}") # Strip surrounding single quotes and whitespace cleaned = [addr.strip().strip("'").strip() for addr in raw] # Filter and deduplicate (case-insensitive) seen = set() filtered = [] for addr in cleaned: lower = addr.lower() # Skip excluded exact addresses if lower in EXCLUDE_EXACT: continue # Skip excluded domain patterns if any(domain in lower for domain in EXCLUDE_DOMAINS): continue # Deduplicate if lower not in seen: seen.add(lower) filtered.append(addr) print(f"[INFO] After filtering and dedup: {len(filtered)} BCC recipients") return filtered def send_notification(token, bcc_recipients): """Send the notification email via Graph API sendMail endpoint.""" subject = 'Security Notice - Do Not Open Box.com File "Valley Wide Plastering, INC......pdf"' body_html = ( '

You recently received a file sharing invitation from my Box.com account ' 'for a file named "Valley Wide Plastering, INC......pdf".

' '\n\n' '

This file was NOT sent by me. My email account was temporarily ' 'compromised, and the attacker used it to distribute this malicious link through ' 'Box.com. The issue has been resolved and my account has been secured.

' '\n\n' '

Please take the following steps:

' '\n' '
    ' '
  1. Do NOT open or click the Box.com link if you haven\'t already
  2. ' '
  3. If you DID click the link or entered any credentials on the page, please ' 'change your password immediately and notify your IT department
  4. ' '
  5. Delete the Box.com sharing notification email from your inbox
  6. ' '
  7. If you created a Box.com account as a result of this invitation, consider removing it
  8. ' '
' '\n\n' '

We apologize for the inconvenience. If you have any questions or concerns, ' 'please contact our office directly.

' '\n\n' '

JR Guerrero
Valley Wide Plastering, Inc.

' ) payload = { "message": { "subject": subject, "body": { "contentType": "HTML", "content": body_html }, "toRecipients": [ {"emailAddress": {"address": JR_EMAIL}} ], "bccRecipients": [ {"emailAddress": {"address": addr}} for addr in bcc_recipients ] }, "saveToSentItems": True } # Write payload to temp file to avoid command-line length limits tmp = tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False, encoding="utf-8") json.dump(payload, tmp, ensure_ascii=False) tmp.close() send_url = f"https://graph.microsoft.com/v1.0/users/{JR_USER_ID}/sendMail" try: result = subprocess.run( [ "curl", "-s", "-o", "/dev/null", "-w", "%{http_code}", "-X", "POST", send_url, "-H", f"Authorization: Bearer {token}", "-H", "Content-Type: application/json", "-d", f"@{tmp.name}", ], capture_output=True, text=True ) status_code = result.stdout.strip() print(f"[INFO] HTTP status code: {status_code}") if status_code == "202": print("[SUCCESS] Notification email sent successfully!") else: print(f"[ERROR] Unexpected status code: {status_code}") # Re-run to capture response body for debugging result2 = subprocess.run( [ "curl", "-s", "-X", "POST", send_url, "-H", f"Authorization: Bearer {token}", "-H", "Content-Type: application/json", "-d", f"@{tmp.name}", ], capture_output=True, text=True ) print(result2.stdout[:2000]) finally: os.unlink(tmp.name) def main(): print("=" * 60) print("VWP BEC Incident - Phishing Notification Sender") print("=" * 60) # Step 1: Load and filter recipients bcc_recipients = load_recipients() # Print all recipients for verification print("\n[INFO] BCC recipient list:") for i, addr in enumerate(bcc_recipients, 1): print(f" {i:3d}. {addr}") print(f"\n[INFO] Total BCC recipients: {len(bcc_recipients)}") print(f"[INFO] To recipient: {JR_EMAIL}") # Step 2: Get access token token = get_access_token() # Step 3: Send the email print(f"\n[INFO] Sending notification email...") send_notification(token, bcc_recipients) print("\n[OK] Done.") if __name__ == "__main__": main()