From c573d0bc51d1193d22288255faf166bdd55bfce9 Mon Sep 17 00:00:00 2001 From: Arathen Date: Fri, 1 Mar 2019 22:27:46 +1100 Subject: [PATCH] IMP: Added new basic email notifier --- data/interfaces/default/config.html | 103 ++++++++++++++++++++++++++++ mylar/PostProcessor.py | 5 ++ mylar/config.py | 11 +++ mylar/notifiers.py | 50 ++++++++++++++ mylar/search.py | 4 ++ mylar/webserve.py | 24 ++++++- 6 files changed, 196 insertions(+), 1 deletion(-) diff --git a/data/interfaces/default/config.html b/data/interfaces/default/config.html index 2846db51..cb7b182c 100755 --- a/data/interfaces/default/config.html +++ b/data/interfaces/default/config.html @@ -1490,6 +1490,58 @@ +
+

Email

+
+ +
+
+
+ + sender@hostname +
+
+ + destination@hostname +
+
+ + Hostname or IP address of your SMTP server +
+
+ + SMTP port - usually 25, 465 or 587 +
+
+ + Username for SMTP server authentication +
+
+ + Password for SMTP server authentication +
+ No encryption   + Use SSL?   + Use TLS? +
+ SMTP server requires TLS or SSL encryption? +
+
+ + Notify when comics are grabbed? +
+
+ + Notify when comics are post processed? +
+
+ +
+ +
+
+
+ @@ -1763,6 +1815,26 @@ } }); + if ($("#email").is(":checked")) + { + $("#emailoptions").show(); + } + else + { + $("#emailoptions").hide(); + } + + $("#email").click(function(){ + if ($("#email").is(":checked")) + { + $("#emailoptions").slideDown(); + } + else + { + $("#emailoptions").slideUp(); + } + }); + if ($("#boxcar").is(":checked")) { $("#boxcaroptions").show(); @@ -2467,6 +2539,37 @@ $('#ajaxMsg').addClass('success').fadeIn().delay(3000).fadeOut(); }); + $('#email_test').click(function () { + var imagechk = document.getElementById("email_statusicon"); + var emailfrom = document.getElementById("email_from").value; + var emailto = document.getElementById("email_to").value; + var emailsvr = document.getElementById("email_server").value; + var emailport = document.getElementById("email_port").value; + var emailuser = document.getElementById("email_user").value; + var emailpass = document.getElementById("email_password").value; + var emailenc = document.querySelector('input[name="email_enc"]:checked').value; // While this causes a browser crash if no radio button is checked, we're ok because we force the default to be checked in the form. + $.get("testemail", + { emailfrom: emailfrom, emailto: emailto, emailsvr: emailsvr, emailport: emailport, emailuser: emailuser, emailpass: emailpass, emailenc: emailenc }, + function(data){ + if (data.error != undefined) { + alert(data.error); + return; + } + $('#emailstatus').val(data); + $('#ajaxMsg').html("
"+data+"
"); + if ( data.indexOf("Successfully") > -1){ + imagechk.src = ""; + imagechk.src = "interfaces/default/images/success.png"; + imagechk.style.visibility = "visible"; + } else { + imagechk.src = ""; + imagechk.src = "interfaces/default/images/fail.png"; + imagechk.style.visibility = "visible"; + } + }); + $('#ajaxMsg').addClass('success').fadeIn().delay(3000).fadeOut(); + }); + $(function() { $( "#tabs" ).tabs(); }); diff --git a/mylar/PostProcessor.py b/mylar/PostProcessor.py index 30c40604..966dccd7 100755 --- a/mylar/PostProcessor.py +++ b/mylar/PostProcessor.py @@ -2796,6 +2796,11 @@ class PostProcessor(object): slack = notifiers.SLACK() slack.notify("Download and Postprocessing completed", prline, module=module) + if mylar.CONFIG.EMAIL_ENABLED and mylar.CONFIG.EMAIL_ONPOST: + logger.info(u"Sending email notification") + email = notifiers.EMAIL() + email.notify(prline2, "Mylar notification - Processed", module=module) + return class FolderCheck(): diff --git a/mylar/config.py b/mylar/config.py index 3652f49f..8b1cf492 100644 --- a/mylar/config.py +++ b/mylar/config.py @@ -186,6 +186,17 @@ _CONFIG_DEFINITIONS = OrderedDict({ 'SLACK_WEBHOOK_URL': (str, 'SLACK', None), 'SLACK_ONSNATCH': (bool, 'SLACK', False), + 'EMAIL_ENABLED': (bool, 'Email', False), + 'EMAIL_FROM': (str, 'Email', ''), + 'EMAIL_TO': (str, 'Email', ''), + 'EMAIL_SERVER': (str, 'Email', ''), + 'EMAIL_USER': (str, 'Email', ''), + 'EMAIL_PASSWORD': (str, 'Email', ''), + 'EMAIL_PORT': (int, 'Email', 25), + 'EMAIL_ENC': (int, 'Email', 0), + 'EMAIL_ONGRAB': (bool, 'Email', True), + 'EMAIL_ONPOST': (bool, 'Email', True), + 'POST_PROCESSING': (bool, 'PostProcess', False), 'FILE_OPTS': (str, 'PostProcess', 'move'), 'SNATCHEDTORRENT_NOTIFY': (bool, 'PostProcess', False), diff --git a/mylar/notifiers.py b/mylar/notifiers.py index 8c741cc3..2342bc33 100644 --- a/mylar/notifiers.py +++ b/mylar/notifiers.py @@ -27,6 +27,9 @@ import time import simplejson import json import requests +import smtplib +from email.mime.multipart import MIMEMultipart +from email.mime.text import MIMEText # This was obviously all taken from headphones with great appreciation :) @@ -479,6 +482,53 @@ class TELEGRAM: def test_notify(self): return self.notify('Test Message: Release the Ninjas!') +class EMAIL: + def __init__(self, test_emailfrom=None, test_emailto=None, test_emailsvr=None, test_emailport=None, test_emailuser=None, test_emailpass=None, test_emailenc=None): + self.emailfrom = mylar.CONFIG.EMAIL_FROM if test_emailfrom is None else test_emailfrom + self.emailto = mylar.CONFIG.EMAIL_TO if test_emailto is None else test_emailto + self.emailsvr = mylar.CONFIG.EMAIL_SERVER if test_emailsvr is None else test_emailsvr + self.emailport = mylar.CONFIG.EMAIL_PORT if test_emailport is None else test_emailport + self.emailuser = mylar.CONFIG.EMAIL_USER if test_emailuser is None else test_emailuser + self.emailpass = mylar.CONFIG.EMAIL_PASSWORD if test_emailpass is None else test_emailpass + self.emailenc = mylar.CONFIG.EMAIL_ENC if test_emailenc is None else int(test_emailenc) + + def notify(self, message, subject, module=None): + if module is None: + module = '' + module += '[NOTIFIER]' + sent_successfully = False + + try: + logger.debug(module + u' Sending email notification. From: [%s] - To: [%s] - Server: [%s] - Port: [%s] - Username: [%s] - Password: [********] - Encryption: [%s] - Message: [%s]' % (self.emailfrom, self.emailto, self.emailsvr, self.emailport, self.emailuser, self.emailenc, message)) + msg = MIMEMultipart() + msg['From'] = str(self.emailfrom) + msg['To'] = str(self.emailto) + msg['Subject'] = subject + msg.attach(MIMEText(message, 'plain')) + + if self.emailenc is 1: + sock = smtplib.SMTP_SSL(self.emailsvr, str(self.emailport)) + else: + sock = smtplib.SMTP(self.emailsvr, str(self.emailport)) + + if self.emailenc is 2: + sock.starttls() + + if self.emailuser or self.emailpass: + sock.login(str(self.emailuser), str(self.emailpass)) + + sock.sendmail(str(self.emailfrom), str(self.emailto), msg.as_string()) + sock.quit() + sent_successfully = True + + except Exception, e: + logger.warn(module + u' Oh no!! Email notification failed: ' + str(e)) + + return sent_successfully + + def test_notify(self): + return self.notify('Test Message: With great power comes great responsibility.', 'Mylar notification - Test') + class SLACK: def __init__(self, test_webhook_url=None): self.webhook_url = mylar.CONFIG.SLACK_WEBHOOK_URL if test_webhook_url is None else test_webhook_url diff --git a/mylar/search.py b/mylar/search.py index 0fe7a90e..c6402ef8 100755 --- a/mylar/search.py +++ b/mylar/search.py @@ -2753,6 +2753,10 @@ def notify_snatch(sent_to, comicname, comyear, IssueNumber, nzbprov, pack): logger.info(u"Sending Slack notification") slack = notifiers.SLACK() slack.notify("Snatched", snline, snatched_nzb=snatched_name, sent_to=sent_to, prov=nzbprov) + if mylar.CONFIG.EMAIL_ENABLED and mylar.CONFIG.EMAIL_ONGRAB: + logger.info(u"Sending email notification") + email = notifiers.EMAIL() + email.notify(snline + " - " + snatched_name, "Mylar notification - Snatch", module="[SEARCH]") return diff --git a/mylar/webserve.py b/mylar/webserve.py index f0ebb80b..30b5d910 100644 --- a/mylar/webserve.py +++ b/mylar/webserve.py @@ -5093,6 +5093,18 @@ class WebInterface(object): "slack_enabled": helpers.checked(mylar.CONFIG.SLACK_ENABLED), "slack_webhook_url": mylar.CONFIG.SLACK_WEBHOOK_URL, "slack_onsnatch": helpers.checked(mylar.CONFIG.SLACK_ONSNATCH), + "email_enabled": helpers.checked(mylar.CONFIG.EMAIL_ENABLED), + "email_from": mylar.CONFIG.EMAIL_FROM, + "email_to": mylar.CONFIG.EMAIL_TO, + "email_server": mylar.CONFIG.EMAIL_SERVER, + "email_user": mylar.CONFIG.EMAIL_USER, + "email_password": mylar.CONFIG.EMAIL_PASSWORD, + "email_port": int(mylar.CONFIG.EMAIL_PORT), + "email_raw": helpers.radio(int(mylar.CONFIG.EMAIL_ENC), 0), + "email_ssl": helpers.radio(int(mylar.CONFIG.EMAIL_ENC), 1), + "email_tls": helpers.radio(int(mylar.CONFIG.EMAIL_ENC), 2), + "email_ongrab": helpers.checked(mylar.CONFIG.EMAIL_ONGRAB), + "email_onpost": helpers.checked(mylar.CONFIG.EMAIL_ONPOST), "enable_extra_scripts": helpers.checked(mylar.CONFIG.ENABLE_EXTRA_SCRIPTS), "extra_scripts": mylar.CONFIG.EXTRA_SCRIPTS, "enable_snatch_script": helpers.checked(mylar.CONFIG.ENABLE_SNATCH_SCRIPT), @@ -5363,7 +5375,7 @@ class WebInterface(object): 'lowercase_filenames', 'autowant_upcoming', 'autowant_all', 'comic_cover_local', 'alternate_latest_series_covers', 'cvinfo', 'snatchedtorrent_notify', 'prowl_enabled', 'prowl_onsnatch', 'nma_enabled', 'nma_onsnatch', 'pushover_enabled', 'pushover_onsnatch', 'boxcar_enabled', 'boxcar_onsnatch', 'pushbullet_enabled', 'pushbullet_onsnatch', 'telegram_enabled', 'telegram_onsnatch', 'slack_enabled', 'slack_onsnatch', - 'opds_enable', 'opds_authentication', 'opds_metainfo', 'enable_ddl'] + 'email_enabled', 'email_enc', 'email_ongrab', 'email_onpost', 'opds_enable', 'opds_authentication', 'opds_metainfo', 'enable_ddl'] for checked_config in checked_configs: if checked_config not in kwargs: @@ -5922,6 +5934,16 @@ class WebInterface(object): return "Error sending test message to Slack" testslack.exposed = True + def testemail(self, emailfrom, emailto, emailsvr, emailport, emailuser, emailpass, emailenc): + email = notifiers.EMAIL(test_emailfrom=emailfrom, test_emailto=emailto, test_emailsvr=emailsvr, test_emailport=emailport, test_emailuser=emailuser, test_emailpass=emailpass, test_emailenc=emailenc) + result = email.test_notify() + + if result == True: + return "Successfully sent email. Check your mailbox." + else: + logger.warn('Email test has gone horribly wrong. Variables used were [FROM: %s] [TO: %s] [SERVER: %s] [PORT: %s] [USER: %s] [PASSWORD: ********] [ENCRYPTION: %s]' % (emailfrom, emailto, emailsvr, emailport, emailuser, emailenc)) + return "Error sending test message via email" + testemail.exposed = True def testrtorrent(self, host, username, password, auth, verify, rpc_url): import torrent.clients.rtorrent as TorClient