Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
Update data_updating_scripts/generate_newsletter.py
Browse files
data_updating_scripts/generate_newsletter.py
CHANGED
|
@@ -306,10 +306,66 @@ def main():
|
|
| 306 |
print(f"Newsletter draft saved: {output_path}")
|
| 307 |
_update_pipeline_progress(1, 1, "newsletter", "Newsletter generated")
|
| 308 |
|
|
|
|
|
|
|
|
|
|
| 309 |
# Upload newsletter draft to HF dataset for persistence
|
| 310 |
_upload_newsletter_to_hf(output_path)
|
| 311 |
|
| 312 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 313 |
def _upload_newsletter_to_hf(draft_path: Path):
|
| 314 |
"""Upload the newsletter draft to HF dataset."""
|
| 315 |
try:
|
|
|
|
| 306 |
print(f"Newsletter draft saved: {output_path}")
|
| 307 |
_update_pipeline_progress(1, 1, "newsletter", "Newsletter generated")
|
| 308 |
|
| 309 |
+
# Email the newsletter
|
| 310 |
+
_send_email_notification(output_path, markdown)
|
| 311 |
+
|
| 312 |
# Upload newsletter draft to HF dataset for persistence
|
| 313 |
_upload_newsletter_to_hf(output_path)
|
| 314 |
|
| 315 |
|
| 316 |
+
def _send_email_notification(draft_path: Path, markdown: str):
|
| 317 |
+
"""Email the newsletter draft to all subscribers + NOTIFY_EMAIL via Gmail SMTP."""
|
| 318 |
+
import smtplib
|
| 319 |
+
from email.mime.multipart import MIMEMultipart
|
| 320 |
+
from email.mime.text import MIMEText
|
| 321 |
+
|
| 322 |
+
gmail_from = os.environ.get("GMAIL_FROM", "").strip()
|
| 323 |
+
app_password = os.environ.get("GMAIL_APP_PASSWORD", "").replace(" ", "")
|
| 324 |
+
notify_to = os.environ.get("NOTIFY_EMAIL", "").strip()
|
| 325 |
+
|
| 326 |
+
if not gmail_from or not app_password:
|
| 327 |
+
logger.info("Email credentials not configured — skipping notification")
|
| 328 |
+
return
|
| 329 |
+
|
| 330 |
+
# Load subscriber list
|
| 331 |
+
subscribers_path = Path("data/subscribers.json")
|
| 332 |
+
subscribers = []
|
| 333 |
+
if subscribers_path.exists():
|
| 334 |
+
try:
|
| 335 |
+
with open(subscribers_path, "r") as f:
|
| 336 |
+
subscribers = json.load(f)
|
| 337 |
+
except Exception:
|
| 338 |
+
pass
|
| 339 |
+
|
| 340 |
+
# Combine subscribers with NOTIFY_EMAIL (deduped)
|
| 341 |
+
all_recipients = list({e.strip().lower() for e in subscribers + ([notify_to] if notify_to else []) if e.strip()})
|
| 342 |
+
|
| 343 |
+
if not all_recipients:
|
| 344 |
+
logger.info("No recipients configured — skipping email")
|
| 345 |
+
return
|
| 346 |
+
|
| 347 |
+
subject = f"VAILL Newsletter — {datetime.now().strftime('%B %d, %Y')}"
|
| 348 |
+
|
| 349 |
+
sent, failed = 0, 0
|
| 350 |
+
with smtplib.SMTP_SSL("smtp.gmail.com", 465) as server:
|
| 351 |
+
server.login(gmail_from, app_password)
|
| 352 |
+
for recipient in all_recipients:
|
| 353 |
+
msg = MIMEMultipart("alternative")
|
| 354 |
+
msg["Subject"] = subject
|
| 355 |
+
msg["From"] = f"VAILL Tracker <{gmail_from}>"
|
| 356 |
+
msg["To"] = recipient
|
| 357 |
+
msg.attach(MIMEText(markdown, "plain", "utf-8"))
|
| 358 |
+
try:
|
| 359 |
+
server.sendmail(gmail_from, recipient, msg.as_string())
|
| 360 |
+
logger.info(f"Newsletter emailed to {recipient}")
|
| 361 |
+
sent += 1
|
| 362 |
+
except Exception as e:
|
| 363 |
+
logger.warning(f"Failed to send to {recipient}: {e}")
|
| 364 |
+
failed += 1
|
| 365 |
+
|
| 366 |
+
print(f"Newsletter sent: {sent} succeeded, {failed} failed ({len(all_recipients)} total recipients)")
|
| 367 |
+
|
| 368 |
+
|
| 369 |
def _upload_newsletter_to_hf(draft_path: Path):
|
| 370 |
"""Upload the newsletter draft to HF dataset."""
|
| 371 |
try:
|