-
Notifications
You must be signed in to change notification settings - Fork 540
Swap sendgrid by SMTP #4551
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Swap sendgrid by SMTP #4551
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,8 @@ | ||
| import asyncio | ||
| import os | ||
| import smtplib | ||
| import ssl | ||
| from email.message import EmailMessage | ||
|
|
||
| import sendgrid | ||
| from sendgrid.helpers.mail import Mail | ||
|
|
@@ -10,7 +14,15 @@ | |
|
|
||
| log = get_logger(__name__) | ||
|
|
||
| # Initialize SendGrid only if enabled | ||
| # Initialize email providers only if enabled | ||
| if env.smtp.enabled: | ||
| log.info("✓ SMTP email enabled") | ||
| else: | ||
| if (env.smtp.host or env.smtp.port) and not env.smtp.from_email: | ||
| log.warn("✗ SMTP disabled: missing sender email address") | ||
| else: | ||
| log.warn("✗ SMTP disabled") | ||
|
Comment on lines
+21
to
+24
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated — replaced the deprecated |
||
|
|
||
| if env.sendgrid.enabled: | ||
| sg = sendgrid.SendGridAPIClient(api_key=env.sendgrid.api_key) | ||
| log.info("✓ SendGrid enabled") | ||
|
|
@@ -54,11 +66,84 @@ async def send_email( | |
| HTTPException: If there is an error sending the email. | ||
| """ | ||
|
|
||
| # No-op if SendGrid is disabled | ||
| if not env.sendgrid.enabled: | ||
| log.info(f"[SENDGRID] Email disabled - would send '{subject}' to {to_email}") | ||
| return True | ||
| if env.smtp.enabled: | ||
| return await _send_smtp_email( | ||
| to_email=to_email, | ||
| subject=subject, | ||
| html_content=html_content, | ||
| from_email=from_email, | ||
| ) | ||
|
|
||
| if env.sendgrid.enabled: | ||
| return await _send_sendgrid_email( | ||
| to_email=to_email, | ||
| subject=subject, | ||
| html_content=html_content, | ||
| from_email=from_email, | ||
| ) | ||
|
|
||
| log.info("[EMAIL] Email disabled - skipping email send") | ||
| return True | ||
|
|
||
|
|
||
| async def _send_smtp_email( | ||
| to_email: str, subject: str, html_content: str, from_email: str | ||
| ) -> bool: | ||
|
Comment on lines
+89
to
+110
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated — moved the blocking |
||
| try: | ||
| return await asyncio.to_thread( | ||
| _send_smtp_email_sync, | ||
| to_email=to_email, | ||
| subject=subject, | ||
| html_content=html_content, | ||
| from_email=from_email, | ||
| ) | ||
| except Exception: | ||
| log.exception("Failed to send SMTP email") | ||
| raise HTTPException( | ||
| status_code=500, | ||
| detail="Failed to send email", | ||
| ) | ||
|
|
||
|
|
||
| def _send_smtp_email_sync( | ||
| to_email: str, subject: str, html_content: str, from_email: str | ||
| ) -> bool: | ||
| message = EmailMessage() | ||
| message["From"] = from_email or env.smtp.from_email | ||
| message["To"] = to_email | ||
| message["Subject"] = subject | ||
| message.set_content(html_content, subtype="html") | ||
|
|
||
| context = ssl.create_default_context() | ||
|
|
||
| if env.smtp.use_ssl: | ||
| with smtplib.SMTP_SSL( | ||
| env.smtp.host, | ||
| env.smtp.port, | ||
| context=context, | ||
| timeout=env.smtp.timeout, | ||
| ) as smtp: | ||
| if env.smtp.username: | ||
| smtp.login(env.smtp.username, env.smtp.password) | ||
| smtp.send_message(message) | ||
| else: | ||
| with smtplib.SMTP( | ||
| env.smtp.host, | ||
| env.smtp.port, | ||
| timeout=env.smtp.timeout, | ||
| ) as smtp: | ||
| if env.smtp.use_tls: | ||
| smtp.starttls(context=context) | ||
| if env.smtp.username: | ||
| smtp.login(env.smtp.username, env.smtp.password) | ||
| smtp.send_message(message) | ||
|
|
||
| return True | ||
|
|
||
|
|
||
| async def _send_sendgrid_email( | ||
| to_email: str, subject: str, html_content: str, from_email: str | ||
| ) -> bool: | ||
| message = Mail( | ||
| from_email=from_email, | ||
| to_emails=to_email, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| from supertokens_python.ingredients.emaildelivery.types import EmailDeliveryConfig | ||
| from supertokens_python.recipe import passwordless | ||
|
|
||
| from oss.src.core.auth.supertokens import config | ||
| from oss.src.utils.env import env | ||
|
|
||
|
|
||
| def _disable_smtp(monkeypatch): | ||
| monkeypatch.setattr(env.smtp, "host", None) | ||
| monkeypatch.setattr(env.smtp, "port", None) | ||
| monkeypatch.setattr(env.smtp, "from_email", None) | ||
| monkeypatch.setattr(env.smtp, "username", None) | ||
| monkeypatch.setattr(env.smtp, "password", None) | ||
| monkeypatch.setattr(env.smtp, "use_ssl", False) | ||
|
|
||
|
|
||
| def _enable_smtp(monkeypatch): | ||
| monkeypatch.setattr(env.smtp, "host", "smtp.example.com") | ||
| monkeypatch.setattr(env.smtp, "port", 1025) | ||
| monkeypatch.setattr(env.smtp, "from_email", "smtp@example.com") | ||
| monkeypatch.setattr(env.smtp, "username", "smtp-user") | ||
| monkeypatch.setattr(env.smtp, "password", "smtp-secret") | ||
| monkeypatch.setattr(env.smtp, "use_ssl", False) | ||
|
|
||
|
|
||
| def test_passwordless_email_delivery_uses_smtp_when_smtp_is_enabled(monkeypatch): | ||
| _enable_smtp(monkeypatch) | ||
|
|
||
| email_delivery = config.get_passwordless_email_delivery() | ||
|
|
||
| assert isinstance(email_delivery, EmailDeliveryConfig) | ||
| assert isinstance(email_delivery.service, passwordless.SMTPService) | ||
| smtp_settings = email_delivery.service.transporter.smtp_settings | ||
| assert smtp_settings.host == "smtp.example.com" | ||
| assert smtp_settings.port == 1025 | ||
| assert smtp_settings.from_.email == "smtp@example.com" | ||
| assert smtp_settings.username == "smtp-user" | ||
| assert smtp_settings.password == "smtp-secret" | ||
| assert smtp_settings.secure is False | ||
|
|
||
|
|
||
| def test_passwordless_email_delivery_is_unset_when_smtp_is_disabled(monkeypatch): | ||
| _disable_smtp(monkeypatch) | ||
|
|
||
| assert config.get_passwordless_email_delivery() is None |
Uh oh!
There was an error while loading. Please reload this page.