forked from phoenix/litellm-mirror
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:
parent
89f314b5ee
commit
070520d237
2 changed files with 53 additions and 19 deletions
|
@ -70,6 +70,7 @@ from litellm.proxy.utils import (
|
||||||
get_instance_fn,
|
get_instance_fn,
|
||||||
ProxyLogging,
|
ProxyLogging,
|
||||||
_cache_user_row,
|
_cache_user_row,
|
||||||
|
send_email,
|
||||||
)
|
)
|
||||||
from litellm.proxy.secret_managers.google_kms import load_google_kms
|
from litellm.proxy.secret_managers.google_kms import load_google_kms
|
||||||
import pydantic
|
import pydantic
|
||||||
|
@ -1742,11 +1743,12 @@ async def user_auth(request: Request):
|
||||||
```
|
```
|
||||||
|
|
||||||
Requirements:
|
Requirements:
|
||||||
This uses [Resend](https://resend.com/) for sending emails. Needs these 2 keys in your .env:
|
SMTP server details saved in .env:
|
||||||
```env
|
- os.environ["SMTP_HOST"]
|
||||||
RESEND_API_KEY = "my-resend-api-key"
|
- os.environ["SMTP_PORT"]
|
||||||
RESEND_API_EMAIL = "my-sending-email"
|
- os.environ["SMTP_USERNAME"]
|
||||||
```
|
- os.environ["SMTP_PASSWORD"]
|
||||||
|
- os.environ["SMTP_SENDER_EMAIL"]
|
||||||
"""
|
"""
|
||||||
global prisma_client
|
global prisma_client
|
||||||
|
|
||||||
|
@ -1756,15 +1758,6 @@ async def user_auth(request: Request):
|
||||||
if user_email is None:
|
if user_email is None:
|
||||||
raise HTTPException(status_code=400, detail="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
|
if prisma_client is None: # if no db connected, raise an error
|
||||||
raise Exception("No connected db.")
|
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/")
|
base_url = os.getenv("LITELLM_HOSTED_UI", "https://dashboard.litellm.ai/")
|
||||||
|
|
||||||
resend.api_key = os.getenv("RESEND_API_KEY")
|
|
||||||
|
|
||||||
params = {
|
params = {
|
||||||
"from": f"LiteLLM Proxy <{os.getenv('RESEND_API_EMAIL')}>",
|
"sender_name": "LiteLLM Proxy",
|
||||||
"to": [user_email],
|
"sender_email": os.getenv("SMTP_SENDER_EMAIL"),
|
||||||
|
"receiver_email": user_email,
|
||||||
"subject": "Your Magic Link",
|
"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>",
|
"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!"
|
return "Email sent!"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,9 @@ from litellm.proxy.hooks.parallel_request_limiter import MaxParallelRequestsHand
|
||||||
from litellm.proxy.hooks.max_budget_limiter import MaxBudgetLimiter
|
from litellm.proxy.hooks.max_budget_limiter import MaxBudgetLimiter
|
||||||
from litellm.integrations.custom_logger import CustomLogger
|
from litellm.integrations.custom_logger import CustomLogger
|
||||||
from fastapi import HTTPException, status
|
from fastapi import HTTPException, status
|
||||||
|
import smtplib
|
||||||
|
from email.mime.text import MIMEText
|
||||||
|
from email.mime.multipart import MIMEMultipart
|
||||||
|
|
||||||
|
|
||||||
def print_verbose(print_statement):
|
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
|
key=cache_key, value=cache_value, ttl=600
|
||||||
) # store for 10 minutes
|
) # store for 10 minutes
|
||||||
return
|
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))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue