def sendmail(self, username, password, message): '''Method to connect to the SMTP server (using TLS security if available) and sending the message through email.''' try: s = smtplib.SMTP(self.server) # Establish TLS code = s.ehlo()[0] usesmtp = 1 if not (200 < code < 299): usesmtp = 0 code = s.helo()[0] if not (200 <= code <= 299): raise smtplib.SMTPHeloError(code) if usesmtp and s.has_extn('starttls'): self.log("Negotiating TLS...") s.starttls() code = s.ehlo()[0] if not (200 <= code <= 299): self.log("Could not EHLO after STARTTLS.") return 0 self.log("Using TLS connection.") else: self.log( "Server does not support TLS; using normal connection.") try: s.login(username, password) except smtplib.SMTPException, e: self.log("Authentication failed: %s" % e) return 0 # mes = self.getmessage(message) s.sendmail(self.fromaddr, self.toaddrs, message) self.log('Message: %s' % message)
def send(self, email): self.container = self.getEmailContainer() if not self.enabled(): self.queue(email, 10) return False server_info = '%s:%d' % (self.container.hostname, self.container.port or 25) try: connection = self.smtp_factory() if self.container.port: port = str(self.container.port) else: port = '25' connection.connect(self.container.hostname, port) code, response = connection.ehlo() if code < 200 or code >= 300: code, response = connection.helo() if code < 200 or code >= 300: raise smtplib.SMTPHeloError(code, response) if connection.has_extn('starttls') and self.container.tls: connection.starttls() connection.ehlo() if connection.does_esmtp: if self.container.username is not None and \ self.container.password is not None: connection.login(self.container.username, self.container.password) except (socket.error, ), e: self.queue(email, 20, {'info': server_info}) return False
def authTLS(self): ''' TLS连接方式的验证 :return:smtp实例 ''' s = smtplib.SMTP() s.connect(mail_server, mail_port) code = s.ehlo()[0] usesesmtp = 1 if not (200 <= code <= 299): usesesmtp = 0 code = s.helo()[0] if not (200 <= code <= 299): raise smtplib.SMTPHeloError(code, resp) if usesesmtp and s.has_extn('starttls'): s.starttls() code = s.ehlo()[0] if not (200 <= code <= 299): sys.exit(5) if s.has_extn('auth'): try: s.login(mail_username, mail_password) except: logger.error("验证失败!") sys.exit(1) self.server = s
def test_expecting_SMTP_helo_error(self) -> None: check = UnitTestSmtpCredentials._create_mocked_method_raising( smtplib.SMTPHeloError(0, '')) status, message = UnitTestSmtpCredentials._run_mocked_check( self.test_expecting_SMTP_helo_error.__name__, check) self.assertEqual( (status, message), (False, smtpcheck.Messages.SMTP_HELO_OR_EHLO_ERROR.value))
def smtp_ehlo_or_helo_if_needed(self, smtp: smtplib.SMTP, name: str = '', disable_ehlo: bool = False) -> NoReturn: if smtp.helo_resp is None and smtp.ehlo_resp is None: if disable_ehlo or not (200 <= smtp.ehlo(name)[0] <= 299): (code, resp) = smtp.helo(name) if not (200 <= code <= 299): raise smtplib.SMTPHeloError(code, resp)
def connect(): """ Establish an smtp connection. """ logger.info('establishing smtp connection with %s using port %d' % (EMAIL_DELIVERY_HOST, EMAIL_DELIVERY_PORT)) conn = smtplib.SMTP(EMAIL_DELIVERY_HOST, EMAIL_DELIVERY_PORT) logger.info('logged in') (code, resp) = conn.ehlo() if not (200 <= code <= 299): raise smtplib.SMTPHeloError(code, resp) conn.starttls() (code, resp) = conn.ehlo() if not (200 <= code <= 299): raise smtplib.SMTPHeloError(code, resp) i = 0 while i <= EMAIL_CONNECTION_RETRIES: i += 1 err = None try: conn.login(EMAIL_DELIVERY_HOST_USER, EMAIL_DELIVERY_HOST_PASSWORD) except smtplib.SMTPAuthenticationError as err: pass if err is None: break else: logger.error('{err.__class__.__name__}: {err}'.format(err=err)) try: conn.quit() except smtplib.SMTPServerDisconnected: pass sleep_time = handle_error(i >= EMAIL_CONNECTION_RETRIES, err, 'connection error', raise_=True) if sleep_time is not None: time.sleep(sleep_time) return conn
async def ehlo_or_helo_if_needed(self): """Call self.ehlo() and/or self.helo() if needed. If there has been no previous EHLO or HELO command this session, this method tries ESMTP EHLO first. This method may raise the following exceptions: SMTPHeloError The server didn't reply properly to the helo greeting. """ if self.helo_resp is None and self.ehlo_resp is None: if not (200 <= await self.ehlo()[0] <= 299): raise smtplib.SMTPHeloError(code, resp)
def test_fallimento_helo(self, mock_smtp): """ In caso di fallimento durante helo il messaggio viene rimesso in coda, tranne che in caso di errore 5XX che è permanente """ self.assertEqual(Messaggio.in_coda().count(), 0) codici = (500, 501, 504, 521, 421) for codice in codici: msg = 'code {}'.format(codice) instance = mock_smtp.return_value instance.sendmail.side_effect = smtplib.SMTPHeloError(code=codice, msg=msg) self._invia_msg_singolo() if codice == 501: self.assertEqual(Messaggio.in_coda().count(), 0) else: self.assertEqual(Messaggio.in_coda().count(), 1) self._reset_coda()
def test_email_plugin(mock_smtp, mock_smtpssl): """ API: NotifyEmail Plugin() """ # Disable Throttling to speed testing plugins.NotifyBase.NotifyBase.request_rate_per_sec = 0 # iterate over our dictionary and test it out for (url, meta) in TEST_URLS: # Our expected instance instance = meta.get('instance', None) # Our expected server objects self = meta.get('self', None) # Our expected Query response (True, False, or exception type) response = meta.get('response', True) test_smtplib_exceptions = meta.get('test_smtplib_exceptions', False) # Our mock of our socket action mock_socket = mock.Mock() mock_socket.starttls.return_value = True mock_socket.login.return_value = True # Create a mock SMTP Object mock_smtp.return_value = mock_socket mock_smtpssl.return_value = mock_socket if test_smtplib_exceptions: # Handle exception testing; first we turn the boolean flag ito # a list of exceptions test_smtplib_exceptions = ( smtplib.SMTPHeloError(0, 'smtplib.SMTPHeloError() not handled'), smtplib.SMTPException(0, 'smtplib.SMTPException() not handled'), RuntimeError(0, 'smtplib.HTTPError() not handled'), smtplib.SMTPRecipientsRefused( 'smtplib.SMTPRecipientsRefused() not handled'), smtplib.SMTPSenderRefused( 0, 'smtplib.SMTPSenderRefused() not handled', '*****@*****.**'), smtplib.SMTPDataError(0, 'smtplib.SMTPDataError() not handled'), smtplib.SMTPServerDisconnected( 'smtplib.SMTPServerDisconnected() not handled'), ) try: obj = Apprise.instantiate(url, suppress_exceptions=False) if obj is None: # We're done (assuming this is what we were expecting) assert instance is None continue if instance is None: # Expected None but didn't get it print('%s instantiated %s (but expected None)' % (url, str(obj))) assert (False) assert (isinstance(obj, instance)) if isinstance(obj, plugins.NotifyBase.NotifyBase): # We loaded okay; now lets make sure we can reverse this url assert (isinstance(obj.url(), six.string_types) is True) # Instantiate the exact same object again using the URL from # the one that was already created properly obj_cmp = Apprise.instantiate(obj.url()) # Our object should be the same instance as what we had # originally expected above. if not isinstance(obj_cmp, plugins.NotifyBase.NotifyBase): # Assert messages are hard to trace back with the way # these tests work. Just printing before throwing our # assertion failure makes things easier to debug later on print('TEST FAIL: {} regenerated as {}'.format( url, obj.url())) assert (False) if self: # Iterate over our expected entries inside of our object for key, val in self.items(): # Test that our object has the desired key assert (hasattr(key, obj)) assert (getattr(key, obj) == val) try: if test_smtplib_exceptions is False: # check that we're as expected assert obj.notify(title='test', body='body', notify_type=NotifyType.INFO) == response else: for exception in test_smtplib_exceptions: mock_socket.sendmail.side_effect = exception try: assert obj.notify( title='test', body='body', notify_type=NotifyType.INFO) is False except AssertionError: # Don't mess with these entries raise except Exception: # We can't handle this exception type raise except AssertionError: # Don't mess with these entries print('%s AssertionError' % url) raise except Exception as e: # Check that we were expecting this exception to happen if not isinstance(e, response): raise except AssertionError: # Don't mess with these entries print('%s AssertionError' % url) raise except Exception as e: # Handle our exception if (instance is None): raise if not isinstance(e, instance): raise
def test_email_plugin(mock_smtp, mock_smtpssl): """ API: NotifyEmail Plugin() """ # iterate over our dictionary and test it out for (url, meta) in TEST_URLS: # Our expected instance instance = meta.get('instance', None) # Our expected exception exception = meta.get('exception', None) # Our expected server objects self = meta.get('self', None) # Our expected Query response (True, False, or exception type) response = meta.get('response', True) test_smtplib_exceptions = meta.get('test_smtplib_exceptions', False) # Our mock of our socket action mock_socket = mock.Mock() mock_socket.starttls.return_value = True mock_socket.login.return_value = True # Create a mock SMTP Object mock_smtp.return_value = mock_socket mock_smtpssl.return_value = mock_socket if test_smtplib_exceptions: # Handle exception testing; first we turn the boolean flag ito # a list of exceptions test_smtplib_exceptions = ( smtplib.SMTPHeloError(0, 'smtplib.SMTPHeloError() not handled'), smtplib.SMTPException(0, 'smtplib.SMTPException() not handled'), RuntimeError(0, 'smtplib.HTTPError() not handled'), smtplib.SMTPRecipientsRefused( 'smtplib.SMTPRecipientsRefused() not handled'), smtplib.SMTPSenderRefused( 0, 'smtplib.SMTPSenderRefused() not handled', '*****@*****.**'), smtplib.SMTPDataError(0, 'smtplib.SMTPDataError() not handled'), smtplib.SMTPServerDisconnected( 'smtplib.SMTPServerDisconnected() not handled'), ) try: obj = Apprise.instantiate(url, suppress_exceptions=False) assert (exception is None) if obj is None: # We're done continue if instance is None: # Expected None but didn't get it print('%s instantiated %s' % (url, str(obj))) assert (False) assert (isinstance(obj, instance)) if self: # Iterate over our expected entries inside of our object for key, val in self.items(): # Test that our object has the desired key assert (hasattr(key, obj)) assert (getattr(key, obj) == val) try: if test_smtplib_exceptions is False: # check that we're as expected assert obj.notify(title='test', body='body', notify_type=NotifyType.INFO) == response else: for exception in test_smtplib_exceptions: mock_socket.sendmail.side_effect = exception try: assert obj.notify( title='test', body='body', notify_type=NotifyType.INFO) is False except AssertionError: # Don't mess with these entries raise except Exception as e: # We can't handle this exception type print('%s / %s' % (url, str(e))) assert False except AssertionError: # Don't mess with these entries raise except Exception as e: # Check that we were expecting this exception to happen assert isinstance(e, response) except AssertionError: # Don't mess with these entries print('%s AssertionError' % url) raise except Exception as e: # Handle our exception print('%s / %s' % (url, str(e))) assert (exception is not None) assert (isinstance(e, exception))
message = """To: %s From:%s Subject: Test Message from simple.py Hello, This is a test message sent to you from simple.py and smtplib. """ % (", ".join(toaddr), fromaddr) try: s = smtplib.SMTP(server) code = s.ehlo()[0] usesesmtp = 1 if not (200 <= code <= 299): usesesmtp = 0 code = s.helo()[0] if not (200 <= code <= 299): raise smtplib.SMTPHeloError(code, msg) if usesesmtp and s.has_extn('starttls'): print("Negotiating TLS...") s.starttls() code = s.ehlo()[0] if not (200 <= code <= 299): print("Couldn't Ehlo after STARTTLS") sys.exit(5) print("Using TLS Connection") else: print("Server does not suppose TLS; using normal connection.") s.sendmail(fromaddr, toaddr, message) except (socket.gaierror, socket.error, socket.herror, smtplib.SMTPException) as e: print("*** Your message may not have been sent !") print(e)
def send_dsn(mailfrom,receiver,msg=None,timeout=600,session=None,ourfrom=''): """Send DSN. If msg is None, do callback verification. Mailfrom is original sender we are sending DSN or CBV to. Receiver is the MTA sending the DSN. Return None for success or (code,msg) for failure.""" user,domain = mailfrom.rsplit('@',1) if not session: session = dns.Session() try: mxlist = session.dns(domain,'MX') except dns.DNSError: return (450,'DNS Timeout: %s MX'%domain) # temp error if not mxlist: mxlist = (0,domain), # fallback to A record when no MX else: mxlist.sort() smtp = smtplib.SMTP() toolate = time.time() + timeout for prior,host in mxlist: try: smtp.connect(host) code,resp = smtp.helo(receiver) # some wiley spammers have MX records that resolve to 127.0.0.1 a = resp.split() if not a: return (553,'MX for %s has no hostname in banner: %s' % (domain,host)) if a[0] == receiver: return (553,'Fraudulent MX for %s: %s' % (domain,host)) if not (200 <= code <= 299): raise smtplib.SMTPHeloError(code, resp) if msg: try: smtp.sendmail('<%s>'%ourfrom,mailfrom,msg) except smtplib.SMTPSenderRefused: # does not accept DSN, try postmaster (at the risk of mail loops) smtp.sendmail('<postmaster@%s>'%receiver,mailfrom,msg) else: # CBV code,resp = smtp.docmd('MAIL FROM: <%s>'%ourfrom) if code != 250: raise smtplib.SMTPSenderRefused(code, resp, '<%s>'%ourfrom) if isinstance(mailfrom,basestring): mailfrom = [mailfrom] badrcpts = {} for rcpt in mailfrom: code,resp = smtp.rcpt(rcpt) if code not in (250,251): badrcpts[rcpt] = (code,resp)# permanent error smtp.quit() if len(badrcpts) == 1: return badrcpts.values()[0] # permanent error if badrcpts: return badrcpts return None # success except smtplib.SMTPRecipientsRefused as x: if len(x.recipients) == 1: return x.recipients.values()[0] # permanent error return x.recipients except smtplib.SMTPSenderRefused as x: return x.args[:2] # does not accept DSN except smtplib.SMTPDataError as x: return x.args # permanent error except smtplib.SMTPException: pass # any other error, try next MX except socket.error: pass # MX didn't accept connections, try next one except socket.timeout: pass # MX too slow, try next one if hasattr(smtp,'sock'): smtp.close() if time.time() > toolate: return (450,'No MX response within %f minutes'%(timeout/60.0)) return (450,'No MX servers available') # temp error