152 lines
4.3 KiB
Python
Executable File
152 lines
4.3 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Sendmail-compatible wrapper for Microsoft Graph email sending.
|
|
Queues emails in maildir format for processing by the sync daemon.
|
|
"""
|
|
|
|
import sys
|
|
import os
|
|
import time
|
|
import logging
|
|
from email.parser import Parser
|
|
from email.utils import parseaddr
|
|
|
|
# Add the project root to Python path
|
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
|
|
from src.utils.mail_utils.helpers import ensure_directory_exists
|
|
|
|
|
|
def extract_org_from_email(email_address: str) -> str:
|
|
"""
|
|
Extract organization name from email address domain.
|
|
|
|
Args:
|
|
email_address: Email address like "user@corteva.com"
|
|
|
|
Returns:
|
|
Organization name (e.g., "corteva")
|
|
"""
|
|
if "@" not in email_address:
|
|
return "default"
|
|
|
|
domain = email_address.split("@")[1].lower()
|
|
|
|
# Map known domains to org names
|
|
domain_to_org = {
|
|
"corteva.com": "corteva",
|
|
# Add more domain mappings as needed
|
|
}
|
|
|
|
return domain_to_org.get(domain, domain.split(".")[0])
|
|
|
|
|
|
def create_outbox_structure(base_path: str, org: str):
|
|
"""
|
|
Create maildir structure for outbox.
|
|
|
|
Args:
|
|
base_path: Base maildir path (e.g., ~/Mail)
|
|
org: Organization name
|
|
"""
|
|
org_path = os.path.join(base_path, org, "outbox")
|
|
ensure_directory_exists(os.path.join(org_path, "new"))
|
|
ensure_directory_exists(os.path.join(org_path, "cur"))
|
|
ensure_directory_exists(os.path.join(org_path, "tmp"))
|
|
ensure_directory_exists(os.path.join(org_path, "failed"))
|
|
|
|
|
|
def queue_email(email_content: str, org: str) -> bool:
|
|
"""
|
|
Queue email in maildir outbox for sending.
|
|
|
|
Args:
|
|
email_content: Raw email content
|
|
org: Organization name
|
|
|
|
Returns:
|
|
True if queued successfully, False otherwise
|
|
"""
|
|
try:
|
|
# Get base maildir path
|
|
base_path = os.path.expanduser(os.getenv("MAILDIR_PATH", "~/Mail"))
|
|
|
|
# Create outbox structure
|
|
create_outbox_structure(base_path, org)
|
|
|
|
# Generate unique filename
|
|
timestamp = str(int(time.time() * 1000000))
|
|
hostname = os.uname().nodename
|
|
filename = f"{timestamp}.{os.getpid()}.{hostname}"
|
|
|
|
# Write to tmp first, then move to new (atomic operation)
|
|
tmp_path = os.path.join(base_path, org, "outbox", "tmp", filename)
|
|
new_path = os.path.join(base_path, org, "outbox", "new", filename)
|
|
|
|
with open(tmp_path, "w", encoding="utf-8") as f:
|
|
f.write(email_content)
|
|
|
|
os.rename(tmp_path, new_path)
|
|
|
|
return True
|
|
|
|
except Exception as e:
|
|
logging.error(f"Failed to queue email: {e}")
|
|
return False
|
|
|
|
|
|
def main():
|
|
"""
|
|
Main sendmail wrapper function.
|
|
Reads email from stdin and queues it for sending.
|
|
"""
|
|
# Set up basic logging
|
|
logging.basicConfig(
|
|
level=logging.INFO,
|
|
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
|
handlers=[
|
|
logging.FileHandler(os.path.expanduser("~/Mail/sendmail.log")),
|
|
]
|
|
)
|
|
|
|
try:
|
|
# Read email from stdin
|
|
email_content = sys.stdin.read()
|
|
|
|
if not email_content.strip():
|
|
logging.error("No email content received")
|
|
sys.exit(1)
|
|
|
|
# Parse email to extract From header
|
|
parser = Parser()
|
|
msg = parser.parsestr(email_content)
|
|
|
|
from_header = msg.get("From", "")
|
|
if not from_header:
|
|
logging.error("No From header found in email")
|
|
sys.exit(1)
|
|
|
|
# Extract email address from From header
|
|
_, from_email = parseaddr(from_header)
|
|
if not from_email:
|
|
logging.error(f"Could not parse email address from From header: {from_header}")
|
|
sys.exit(1)
|
|
|
|
# Determine organization from email domain
|
|
org = extract_org_from_email(from_email)
|
|
|
|
# Queue the email
|
|
if queue_email(email_content, org):
|
|
logging.info(f"Email queued successfully for org: {org}, from: {from_email}")
|
|
sys.exit(0)
|
|
else:
|
|
logging.error("Failed to queue email")
|
|
sys.exit(1)
|
|
|
|
except Exception as e:
|
|
logging.error(f"Sendmail wrapper error: {e}")
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main() |