mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-06 02:48:13 +00:00
Litellm emails smtp fixes (#10730)
* feat: smtp email logger * feat: smtp email logger * fix: linting errors
This commit is contained in:
parent
037b2f9033
commit
07cb100fdc
5 changed files with 91 additions and 7 deletions
|
|
@ -0,0 +1,47 @@
|
|||
"""
|
||||
This is the litellm SMTP email integration
|
||||
"""
|
||||
import asyncio
|
||||
from typing import List
|
||||
|
||||
from litellm._logging import verbose_logger
|
||||
|
||||
from .base_email import BaseEmailLogger
|
||||
|
||||
|
||||
class SMTPEmailLogger(BaseEmailLogger):
|
||||
"""
|
||||
This is the litellm SMTP email integration
|
||||
|
||||
Required SMTP environment variables:
|
||||
- SMTP_HOST
|
||||
- SMTP_PORT
|
||||
- SMTP_USERNAME
|
||||
- SMTP_PASSWORD
|
||||
- SMTP_SENDER_EMAIL
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
verbose_logger.debug("SMTP Email Logger initialized....")
|
||||
|
||||
async def send_email(
|
||||
self,
|
||||
from_email: str,
|
||||
to_email: List[str],
|
||||
subject: str,
|
||||
html_body: str,
|
||||
):
|
||||
from litellm.proxy.utils import send_email as send_smtp_email
|
||||
|
||||
verbose_logger.debug(
|
||||
f"Sending email from {from_email} to {to_email} with subject {subject}"
|
||||
)
|
||||
for receiver_email in to_email:
|
||||
asyncio.create_task(
|
||||
send_smtp_email(
|
||||
receiver_email=receiver_email,
|
||||
subject=subject,
|
||||
html=html_body,
|
||||
)
|
||||
)
|
||||
return
|
||||
|
|
@ -117,6 +117,7 @@ _custom_logger_compatible_callbacks_literal = Literal[
|
|||
"bedrock_vector_store",
|
||||
"generic_api",
|
||||
"resend_email",
|
||||
"smtp_email",
|
||||
]
|
||||
logged_real_time_event_types: Optional[Union[List[str], Literal["*"]]] = None
|
||||
_known_custom_logger_compatible_callbacks: List = list(
|
||||
|
|
|
|||
|
|
@ -140,13 +140,16 @@ try:
|
|||
from litellm_enterprise.enterprise_callbacks.send_emails.resend_email import (
|
||||
ResendEmailLogger,
|
||||
)
|
||||
from litellm_enterprise.enterprise_callbacks.send_emails.smtp_email import (
|
||||
SMTPEmailLogger,
|
||||
)
|
||||
except Exception as e:
|
||||
verbose_logger.debug(
|
||||
f"[Non-Blocking] Unable to import GenericAPILogger - LiteLLM Enterprise Feature - {str(e)}"
|
||||
)
|
||||
GenericAPILogger = CustomLogger # type: ignore
|
||||
ResendEmailLogger = CustomLogger # type: ignore
|
||||
|
||||
SMTPEmailLogger = CustomLogger # type: ignore
|
||||
_in_memory_loggers: List[Any] = []
|
||||
|
||||
### GLOBAL VARIABLES ###
|
||||
|
|
@ -3053,6 +3056,13 @@ def _init_custom_logger_compatible_class( # noqa: PLR0915
|
|||
resend_email_logger = ResendEmailLogger()
|
||||
_in_memory_loggers.append(resend_email_logger)
|
||||
return resend_email_logger # type: ignore
|
||||
elif logging_integration == "smtp_email":
|
||||
for callback in _in_memory_loggers:
|
||||
if isinstance(callback, SMTPEmailLogger):
|
||||
return callback
|
||||
smtp_email_logger = SMTPEmailLogger()
|
||||
_in_memory_loggers.append(smtp_email_logger)
|
||||
return smtp_email_logger # type: ignore
|
||||
elif logging_integration == "humanloop":
|
||||
for callback in _in_memory_loggers:
|
||||
if isinstance(callback, HumanloopLogger):
|
||||
|
|
@ -3204,6 +3214,10 @@ def get_custom_logger_compatible_class( # noqa: PLR0915
|
|||
for callback in _in_memory_loggers:
|
||||
if isinstance(callback, ResendEmailLogger):
|
||||
return callback
|
||||
elif logging_integration == "smtp_email":
|
||||
for callback in _in_memory_loggers:
|
||||
if isinstance(callback, SMTPEmailLogger):
|
||||
return callback
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ model_list:
|
|||
|
||||
|
||||
litellm_settings:
|
||||
callbacks: ["resend_email"]
|
||||
callbacks: ["smtp_email"]
|
||||
|
||||
guardrails:
|
||||
- guardrail_name: "bedrock-pre-guard"
|
||||
|
|
|
|||
|
|
@ -2362,7 +2362,11 @@ async def _cache_user_row(user_id: str, cache: DualCache, db: PrismaClient):
|
|||
return
|
||||
|
||||
|
||||
async def send_email(receiver_email, subject, html):
|
||||
async def send_email(
|
||||
receiver_email: Optional[str] = None,
|
||||
subject: Optional[str] = None,
|
||||
html: Optional[str] = None,
|
||||
):
|
||||
"""
|
||||
smtp_host,
|
||||
smtp_port,
|
||||
|
|
@ -2380,6 +2384,12 @@ async def send_email(receiver_email, subject, html):
|
|||
sender_email = os.getenv("SMTP_SENDER_EMAIL", None)
|
||||
if sender_email is None:
|
||||
raise ValueError("Trying to use SMTP, but SMTP_SENDER_EMAIL is not set")
|
||||
if receiver_email is None:
|
||||
raise ValueError(f"No receiver email provided for SMTP email. {receiver_email}")
|
||||
if subject is None:
|
||||
raise ValueError(f"No subject provided for SMTP email. {subject}")
|
||||
if html is None:
|
||||
raise ValueError(f"No HTML body provided for SMTP email. {html}")
|
||||
|
||||
## EMAIL SETUP ##
|
||||
email_message = MIMEMultipart()
|
||||
|
|
@ -2398,19 +2408,31 @@ async def send_email(receiver_email, subject, html):
|
|||
|
||||
try:
|
||||
# Establish a secure connection with the SMTP server
|
||||
with smtplib.SMTP(smtp_host, smtp_port) as server: # type: ignore
|
||||
with smtplib.SMTP(
|
||||
host=smtp_host,
|
||||
port=smtp_port,
|
||||
) as server:
|
||||
if os.getenv("SMTP_TLS", "True") != "False":
|
||||
server.starttls()
|
||||
|
||||
# Login to your email account only if smtp_username and smtp_password are provided
|
||||
if smtp_username and smtp_password:
|
||||
server.login(smtp_username, smtp_password) # type: ignore
|
||||
server.login(
|
||||
user=smtp_username,
|
||||
password=smtp_password,
|
||||
)
|
||||
|
||||
# Send the email
|
||||
server.send_message(email_message)
|
||||
server.send_message(
|
||||
msg=email_message,
|
||||
from_addr=sender_email,
|
||||
to_addrs=receiver_email,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
print_verbose("An error occurred while sending the email:" + str(e))
|
||||
verbose_proxy_logger.exception(
|
||||
"An error occurred while sending the email:" + str(e)
|
||||
)
|
||||
|
||||
|
||||
def hash_token(token: str):
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue