From 16a7ceb8ea5b341c6b91b763380090358f000e1b Mon Sep 17 00:00:00 2001 From: Harvey Tindall Date: Sun, 26 Apr 2020 21:28:55 +0100 Subject: [PATCH] Added STARTTLS for SMTP As many services don't support full encryption, there is now an encryption option in the [smtp] section, allowing you to choose between ssl_tls and starttls. --- README.md | 8 ++++---- data/config-default.ini | 4 ++-- jellyfin_accounts/email.py | 33 +++++++++++++++++++++++---------- 3 files changed, 29 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 583754d..5375e4e 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ optional arguments: #### Emails/Password Resets * When someone initiates forget password on Jellyfin, a file named `passwordreset*.json` is created in its configuration directory. This directory is monitored and when created, the program reads the username, expiry time and PIN, puts it into a template and sends it to whatever address is specified in `emails.json`. * **The default forget password popup references the `passwordreset*.json` file created. This is confusing for users, so a quick fix is to edit the `MessageForgotPasswordFileCreated` string in Jellyfin's language folder.** -* Currently, jellyfin-accounts supports generic SSL/TLS secured SMTP, and the [mailgun](https://mailgun.com) REST API. +* Currently, jellyfin-accounts supports generic SSL/TLS or STARTTLS secured SMTP, and the [mailgun](https://mailgun.com) REST API. * Email html is created using [mjml](https://mjml.io), and [jinja](https://github.com/pallets/jinja) templating is used. If you wish to create your own, ensure you use the same jinja expressions (`{{ pin }}`, etc.) as used in `data/email.mjml` or `invite-email.mjml`, and also create plain text versions for legacy email clients. #### Configuration @@ -177,11 +177,11 @@ api_url = https://api.mailgun.net... api_key = your api key [smtp] -; Insecure SMTP hasn't been implemented, although I doubt many will need it. -ssl = true +; Choose between ssl_tls and starttls. Your provider should tell you which to use, but generally SSL/TLS is 465, STARTTLS 587 +encryption = starttls server = smtp.jellyf.in ; Uses SMTP_SSL, so make sure the port is for this, not starttls. -port = 465 +port = 587 password = smtp password [files] diff --git a/data/config-default.ini b/data/config-default.ini index 66eda7d..453d511 100644 --- a/data/config-default.ini +++ b/data/config-default.ini @@ -88,8 +88,8 @@ api_url = https://api.mailgun.net... api_key = your api key [smtp] -; Insecure SMTP hasn't been implemented, although I doubt many will need it. -ssl = true +; Choose between ssl_tls and starttls. Your provider should tell you which to use, but generally SSL/TLS is 465, STARTTLS 587 +encryption = starttls server = smtp.jellyf.in ; Uses SMTP_SSL, so make sure the port is for this, not starttls. port = 465 diff --git a/jellyfin_accounts/email.py b/jellyfin_accounts/email.py index b1d977d..a75c1b7 100644 --- a/jellyfin_accounts/email.py +++ b/jellyfin_accounts/email.py @@ -139,7 +139,6 @@ class Smtp(Email): except ValueError: self.port = 465 log.debug(f'{self.address}: Defaulting to port {self.port}') - self.context = ssl.create_default_context() def send(self): message = MIMEMultipart("alternative") @@ -151,15 +150,29 @@ class Smtp(Email): message.attach(text) message.attach(html) try: - with smtplib.SMTP_SSL(self.server, - self.port, - context=self.context) as server: - server.login(self.from_address, self.password) - server.sendmail(self.from_address, - self.address, - message.as_string()) - log.info(f'{self.address}: Sent via smtp') - return True + if config['smtp']['encryption'] == 'ssl_tls': + self.context = ssl.create_default_context() + with smtplib.SMTP_SSL(self.server, + self.port, + context=self.context) as server: + server.ehlo() + server.login(self.from_address, self.password) + server.sendmail(self.from_address, + self.address, + message.as_string()) + log.info(f'{self.address}: Sent via smtp (ssl/tls)') + return True + elif config['smtp']['encryption'] == 'starttls': + with smtplib.SMTP(self.server, + self.port) as server: + server.ehlo() + server.starttls() + server.login(self.from_address, self.password) + server.sendmail(self.from_address, + self.address, + message.as_string()) + log.info(f'{self.address}: Sent via smtp (starttls)') + return True except Exception as e: err = f'{self.address}: Failed to send via smtp: ' err += type(e).__name__