26:def build_mime_message( 83:def validate_html(html: str) -> List[str]: 104:def html_to_pdf(html: str) -> bytes: 129:def generate_attachment_filename(kind: str, invoice_number: str) -> str: --- def send_mime_api(self, mime_message) -> dict: """Send via Gmail API users.messages.send. Returns real provider response.""" service = self._api() raw = base64.urlsafe_b64encode(mime_message.as_bytes()).decode() body = {"raw": raw} sent = service.users().messages().send(userId="me", body=body).execute() return {"ok": True, "message_id": sent.get("id", ""), "thread_id": sent.get("threadId", ""), "label_ids": sent.get("labelIds", []), "raw_response": sent} # -- SMTP send (XOAUTH2, no password) ------------------------------------- def send_mime_smtp(self, mime_message) -> dict: import smtplib from email.utils import parseaddr self._ensure_valid() access_token = self._creds.token auth_string = f"user={self.account_email}\x01auth=Bearer {access_token}\x01\x01" with smtplib.SMTP("smtp.gmail.com", 587, timeout=30) as smtp: smtp.ehlo() smtp.starttls(context=__import__("ssl").create_default_context()) smtp.ehlo() code, response = smtp.docmd("AUTH", "XOAUTH2 " + base64.b64encode(auth_string.encode()).decode()) refused = smtp.sendmail(self.account_email, [parseaddr(mime_message["To"])[1]], mime_message.as_bytes()) if refused: return {"ok": False, "error": f"SMTP refused recipients: {refused}", "error_class": "permanent"} return {"ok": True, "message_id": "", "thread_id": "", "raw_response": f"250 SMTP accepted ({code} {response.decode(errors='replace')})"} # -- Health / profile ------------------------------------------------------ def get_profile(self) -> dict: ---CELERY--- """Celery application: Redis broker, task routing, beat schedule.""" import logging import os from celery import Celery from kombu import Queue from app.core.config import settings log = logging.getLogger("celery") redis_url = settings.REDIS_URL broker_url = redis_url if redis_url.endswith("/0") else redis_url if not broker_url.endswith(str(settings.CELERY_BROKER_DB)): broker_url = broker_url.rstrip("0123456789") + str(settings.CELERY_BROKER_DB) result_backend = broker_url.rstrip("0123456789") + str(settings.CELERY_RESULT_DB) celery_app = Celery( "bulkgmailmailer", broker=broker_url, backend=result_backend, include=["app.tasks.send_tasks"], ) celery_app.conf.update( task_serializer="json", accept_content=["json"], result_serializer="json", timezone="UTC", enable_utc=True, task_acks_late=True, task_reject_on_worker_lost=True, worker_prefetch_multiplier=1, # strict sequential-like processing per worker task_default_queue="send", task_queues=(Queue("send", routing_key="send.#"), Queue("control", routing_key="control.#")), task_routes={"app.tasks.send_tasks.send_one": {"queue": "send"}, "app.tasks.send_tasks.*": {"queue": "send"}}, broker_connection_retry_on_startup=True, task_track_started=True, task_time_limit=120, task_soft_time_limit=100, # Rate limiting is applied per-account inside tasks via Redis; global default: worker_concurrency=2, )