import smtplib from datetime import datetime from email.mime.image import MIMEImage from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.utils import formatdate from email.utils import make_msgid from onyx.configs.app_configs import EMAIL_CONFIGURED from onyx.configs.app_configs import EMAIL_FROM from onyx.configs.app_configs import SMTP_PASS from onyx.configs.app_configs import SMTP_PORT from onyx.configs.app_configs import SMTP_SERVER from onyx.configs.app_configs import SMTP_USER from onyx.configs.app_configs import WEB_DOMAIN from onyx.configs.constants import AuthType from onyx.configs.constants import ONYX_DEFAULT_APPLICATION_NAME from onyx.configs.constants import ONYX_SLACK_URL from onyx.db.models import User from onyx.server.runtime.onyx_runtime import OnyxRuntime from onyx.utils.file import FileWithMimeType from onyx.utils.url import add_url_params from onyx.utils.variable_functionality import fetch_versioned_implementation from shared_configs.configs import MULTI_TENANT HTML_EMAIL_TEMPLATE = """\
![]() |
{heading}{cta_block} |
© {year} {application_name}. All rights reserved. {slack_fragment} |
We're sorry to see you go.
" "Your subscription has been canceled and will end on your next billing date.
" "If you change your mind, you can always come back!
" ) cta_text = "Renew Subscription" cta_link = "https://www.onyx.app/pricing" html_content = build_html_email( application_name, heading, message, cta_text, cta_link, ) text_content = ( "We're sorry to see you go.\n" "Your subscription has been canceled and will end on your next billing date.\n" "If you change your mind, visit https://www.onyx.app/pricing" ) send_email( user_email, subject, html_content, text_content, inline_png=("logo.png", onyx_file.data), ) def send_user_email_invite( user_email: str, current_user: User, auth_type: AuthType ) -> None: onyx_file: FileWithMimeType | None = None try: load_runtime_settings_fn = fetch_versioned_implementation( "onyx.server.enterprise_settings.store", "load_runtime_settings" ) settings = load_runtime_settings_fn() application_name = settings.application_name except ModuleNotFoundError: application_name = ONYX_DEFAULT_APPLICATION_NAME onyx_file = OnyxRuntime.get_emailable_logo() subject = f"Invitation to Join {application_name} Organization" heading = "You've Been Invited!" # the exact action taken by the user, and thus the message, depends on the auth type message = f"You have been invited by {current_user.email} to join an organization on {application_name}.
" if auth_type == AuthType.CLOUD: message += ( "To join the organization, please click the button below to set a password " "or login with Google and complete your registration.
" ) elif auth_type == AuthType.BASIC: message += ( "To join the organization, please click the button below to set a password " "and complete your registration.
" ) elif auth_type == AuthType.GOOGLE_OAUTH: message += ( "To join the organization, please click the button below to login with Google " "and complete your registration.
" ) elif auth_type == AuthType.OIDC or auth_type == AuthType.SAML: message += ( "To join the organization, please click the button below to" " complete your registration.
" ) else: raise ValueError(f"Invalid auth type: {auth_type}") cta_text = "Join Organization" cta_link = f"{WEB_DOMAIN}/auth/signup?email={user_email}" html_content = build_html_email( application_name, heading, message, cta_text, cta_link, ) # text content is the fallback for clients that don't support HTML # not as critical, so not having special cases for each auth type text_content = ( f"You have been invited by {current_user.email} to join an organization on {application_name}.\n" "To join the organization, please visit the following link:\n" f"{WEB_DOMAIN}/auth/signup?email={user_email}\n" ) if auth_type == AuthType.CLOUD: text_content += "You'll be asked to set a password or login with Google to complete your registration." send_email( user_email, subject, html_content, text_content, inline_png=("logo.png", onyx_file.data), ) def send_forgot_password_email( user_email: str, token: str, tenant_id: str, mail_from: str = EMAIL_FROM, ) -> None: # Builds a forgot password email with or without fancy HTML try: load_runtime_settings_fn = fetch_versioned_implementation( "onyx.server.enterprise_settings.store", "load_runtime_settings" ) settings = load_runtime_settings_fn() application_name = settings.application_name except ModuleNotFoundError: application_name = ONYX_DEFAULT_APPLICATION_NAME onyx_file = OnyxRuntime.get_emailable_logo() subject = f"Reset Your {application_name} Password" heading = "Reset Your Password" tenant_param = f"&tenant={tenant_id}" if tenant_id and MULTI_TENANT else "" message = "Please click the button below to reset your password. This link will expire in 24 hours.
" cta_text = "Reset Password" cta_link = f"{WEB_DOMAIN}/auth/reset-password?token={token}{tenant_param}" html_content = build_html_email( application_name, heading, message, cta_text, cta_link, ) text_content = ( f"Please click the following link to reset your password. This link will expire in 24 hours.\n" f"{WEB_DOMAIN}/auth/reset-password?token={token}{tenant_param}" ) send_email( user_email, subject, html_content, text_content, mail_from, inline_png=("logo.png", onyx_file.data), ) def send_user_verification_email( user_email: str, token: str, new_organization: bool = False, mail_from: str = EMAIL_FROM, ) -> None: # Builds a verification email try: load_runtime_settings_fn = fetch_versioned_implementation( "onyx.server.enterprise_settings.store", "load_runtime_settings" ) settings = load_runtime_settings_fn() application_name = settings.application_name except ModuleNotFoundError: application_name = ONYX_DEFAULT_APPLICATION_NAME onyx_file = OnyxRuntime.get_emailable_logo() subject = f"{application_name} Email Verification" link = f"{WEB_DOMAIN}/auth/verify-email?token={token}" if new_organization: link = add_url_params(link, {"first_user": "true"}) message = ( f"Click the following link to verify your email address:
{link}
" ) html_content = build_html_email( application_name, "Verify Your Email", message, ) text_content = f"Click the following link to verify your email address: {link}" send_email( user_email, subject, html_content, text_content, mail_from, inline_png=("logo.png", onyx_file.data), )