import smtplib
import os
from email.message import EmailMessage
msg = EmailMessage()
msg["Subject"] = "Monthly Report"
msg["From"] = "you@yourdomain.com"
msg["To"] = "boss@yourdomain.com"
msg.set_content("Hi — attached is the monthly report.\n\nThanks,\nYou")
# Attach a file
with open("report.xlsx", "rb") as f:
msg.add_attachment(
f.read(),
maintype="application",
subtype="vnd.openxmlformats-officedocument.spreadsheetml.sheet",
filename="report.xlsx",
)
with smtplib.SMTP_SSL("smtp.gmail.com", 465) as smtp:
smtp.login(os.environ["EMAIL_USER"], os.environ["EMAIL_PASS"])
smtp.send_message(msg)
print("Sent.")
os.environ["EMAIL_PASS"]), a .env file loaded with python-dotenv, or a system secret manager. Never check credentials into version control.
Big providers now require app-specific passwords or OAuth. The cleanest libraries:
O365 library (pip install O365) which wraps the Microsoft Graph API.for _, row in customers.iterrows():
msg = EmailMessage()
msg["Subject"] = f"Your {row['month']} statement"
msg["From"] = "you@yourdomain.com"
msg["To"] = row["email"]
msg.set_content(f"""Hi {row['first_name']},
Your statement for {row['month']} is attached.
Best,
You""")
with open(row["attachment"], "rb") as f:
msg.add_attachment(f.read(),
maintype="application",
subtype="pdf",
filename=Path(row["attachment"]).name)
with smtplib.SMTP_SSL("smtp.gmail.com", 465) as smtp:
smtp.login(os.environ["EMAIL_USER"], os.environ["EMAIL_PASS"])
smtp.send_message(msg)
smtplib sends mail; EmailMessage formats it.Send yourself a test email with an attached CSV. Confirm it lands. Then do the same for three rows of a small DataFrame.