fix(proxy_server.py): support smtp email auth

previously was a hard resend package dependency. removed in favor of allowing any smtp server connection (including resend)
This commit is contained in:
Krrish Dholakia 2024-01-02 22:22:08 +05:30
parent 89f314b5ee
commit 070520d237
2 changed files with 53 additions and 19 deletions

View file

@ -70,6 +70,7 @@ from litellm.proxy.utils import (
get_instance_fn,
ProxyLogging,
_cache_user_row,
send_email,
)
from litellm.proxy.secret_managers.google_kms import load_google_kms
import pydantic
@ -1742,11 +1743,12 @@ async def user_auth(request: Request):
```
Requirements:
This uses [Resend](https://resend.com/) for sending emails. Needs these 2 keys in your .env:
```env
RESEND_API_KEY = "my-resend-api-key"
RESEND_API_EMAIL = "my-sending-email"
```
SMTP server details saved in .env:
- os.environ["SMTP_HOST"]
- os.environ["SMTP_PORT"]
- os.environ["SMTP_USERNAME"]
- os.environ["SMTP_PASSWORD"]
- os.environ["SMTP_SENDER_EMAIL"]
"""
global prisma_client
@ -1756,15 +1758,6 @@ async def user_auth(request: Request):
if user_email is None:
raise HTTPException(status_code=400, detail="User email is none")
import os
try:
import resend
except ImportError:
raise Exception(
"Resend package missing. Run `pip install litellm[extra_proxy]` to add missing dependencies."
)
if prisma_client is None: # if no db connected, raise an error
raise Exception("No connected db.")
@ -1785,16 +1778,15 @@ async def user_auth(request: Request):
base_url = os.getenv("LITELLM_HOSTED_UI", "https://dashboard.litellm.ai/")
resend.api_key = os.getenv("RESEND_API_KEY")
params = {
"from": f"LiteLLM Proxy <{os.getenv('RESEND_API_EMAIL')}>",
"to": [user_email],
"sender_name": "LiteLLM Proxy",
"sender_email": os.getenv("SMTP_SENDER_EMAIL"),
"receiver_email": user_email,
"subject": "Your Magic Link",
"html": f"<strong> Follow this link, to login:\n\n{base_url}user/?token={response['token']}&user_id={response['user_id']}&page={page_params}</strong>",
}
email = resend.Emails.send(params)
await send_email(**params)
return "Email sent!"

View file

@ -7,6 +7,9 @@ from litellm.proxy.hooks.parallel_request_limiter import MaxParallelRequestsHand
from litellm.proxy.hooks.max_budget_limiter import MaxBudgetLimiter
from litellm.integrations.custom_logger import CustomLogger
from fastapi import HTTPException, status
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
def print_verbose(print_statement):
@ -548,3 +551,42 @@ async def _cache_user_row(user_id: str, cache: DualCache, db: PrismaClient):
key=cache_key, value=cache_value, ttl=600
) # store for 10 minutes
return
async def send_email(sender_name, sender_email, receiver_email, subject, html):
"""
smtp_host,
smtp_port,
smtp_username,
smtp_password,
sender_name,
sender_email,
"""
## SERVER SETUP ##
smtp_host = os.getenv("SMTP_HOST")
smtp_port = os.getenv("SMTP_PORT", 587) # default to port 587
smtp_username = os.getenv("SMTP_USERNAME")
smtp_password = os.getenv("SMTP_PASSWORD")
## EMAIL SETUP ##
email_message = MIMEMultipart()
email_message["From"] = f"{sender_name} <{sender_email}>"
email_message["To"] = receiver_email
email_message["Subject"] = subject
# Attach the body to the email
email_message.attach(MIMEText(html, "html"))
try:
print_verbose(f"SMTP Connection Init")
# Establish a secure connection with the SMTP server
with smtplib.SMTP(smtp_host, smtp_port) as server:
server.starttls()
# Login to your email account
server.login(smtp_username, smtp_password)
# Send the email
server.send_message(email_message)
except Exception as e:
print_verbose("An error occurred while sending the email:", str(e))