예제 #1
0
 def test_hostname_empty(self):
     # WARNING: This test _always_ succeeds in Windows.
     cont = Controller(Sink(), hostname="")
     try:
         cont.start()
     finally:
         cont.stop()
예제 #2
0
def main(keywords, antivirus, in_port, server, port):
    in_port = in_port if in_port else IN_PORT
    server = server if server else MAIL_SERVER
    port = port if port else OUT_PORT

    filters = []
    # add keyword filters if specified
    if keywords:
        keywords = keywords.split(",")
        for k in keywords:
            if not isfile(abspath(k)):
                print("%s: keywords file does not exist" % k)
            else:
                filters.append(KeywordFilter(k))
    # add antivirus filter if specified
    if antivirus:
        filters.append(AntivirusFilter())

    # create a gateway object containing the filters, start the server
    gateway = Gateway(server, port, filters)
    controller = Controller(MailHandler(gateway),
                            hostname='localhost',
                            port=in_port)
    try:
        controller.start()
        while True:
            pass
    finally:
        controller.stop()
예제 #3
0
    def test_real_mail_aiosmtpd(self):
        """ Test sending messages with a real-world SMTPD server """
        if aiosmtpd is None:
            self.skipTest('aiosmtpd not available')

        # Start an smtp server
        mail_handler = StashingHandler()
        controller = Controller(mail_handler, loop=None,
                                hostname='localhost', port=self.smtpd_port)
        controller.start()

        # Give it time to settle
        sleep(0.5)

        # Initialize a Postman
        postman = Postman('*****@*****.**',
                          NoLoginSMTP('localhost', self.smtpd_port, None, None))

        # Send messages
        with postman.connect() as c:
            # Send plaintext message
            msg = Message(['*****@*****.**'], 'Subject', 'HTML message')
            c.sendmail(msg)

            # Send unicode message
            msg = Message(['*****@*****.**'], u'Håkon', u'Håkon')
            c.sendmail(msg)

        # Done
        controller.stop()

        # Test
        self.assertEqual(len(mail_handler.mail), 2)
예제 #4
0
 def test_reuse_loop(self, temp_event_loop):
     cont = Controller(Sink(), loop=temp_event_loop)
     assert cont.loop is temp_event_loop
     try:
         cont.start()
         assert cont.smtpd.loop is temp_event_loop
     finally:
         cont.stop()
예제 #5
0
 def test_normal_situation(self):
     cont = Controller(Sink())
     try:
         cont.start()
         assert cont.smtpd is not None
         assert cont._thread_exception is None
     finally:
         cont.stop()
예제 #6
0
 def test_socket_error_dupe(self, plain_controller, client):
     contr2 = Controller(Sink(),
                         hostname=Global.SrvAddr.host,
                         port=Global.SrvAddr.port)
     try:
         with pytest.raises(socket.error):
             contr2.start()
     finally:
         contr2.stop()
예제 #7
0
 def test_server_attribute(self):
     controller = Controller(Sink())
     self.assertIsNone(controller.server)
     try:
         controller.start()
         self.assertIsNotNone(controller.server)
     finally:
         controller.stop()
         self.assertIsNone(controller.server)
예제 #8
0
 def test_server_attribute(self):
     controller = Controller(Sink())
     self.assertIsNone(controller.server)
     try:
         controller.start()
         self.assertIsNotNone(controller.server)
     finally:
         controller.stop()
         self.assertIsNone(controller.server)
예제 #9
0
 def test_testconn_raises(self, mocker: MockFixture):
     mocker.patch("socket.socket.recv",
                  side_effect=RuntimeError("MockError"))
     cont = Controller(Sink(), hostname="")
     try:
         with pytest.raises(RuntimeError, match="MockError"):
             cont.start()
     finally:
         cont.stop()
예제 #10
0
 def test_server_attribute(self):
     controller = Controller(Sink())
     assert controller.server is None
     try:
         controller.start()
         assert controller.server is not None
     finally:
         controller.stop()
     assert controller.server is None
예제 #11
0
파일: server.py 프로젝트: wevsty/aiosmtpd
async def amain():
    handler = RelayHandler()
    cont = Controller(handler,
                      hostname='',
                      port=8025,
                      authenticator=Authenticator(DB_AUTH))
    try:
        cont.start()
    finally:
        cont.stop()
예제 #12
0
 def test_socket_error_dupe(self, plain_controller, client):
     contr2 = Controller(Sink(),
                         hostname=Global.SrvAddr.host,
                         port=Global.SrvAddr.port)
     expectedre = r"error while attempting to bind on address"
     try:
         with pytest.raises(socket.error, match=expectedre):
             contr2.start()
     finally:
         contr2.stop()
예제 #13
0
 def test_unknown_args_direct(self, silence_event_loop_closed):
     unknown = "this_is_an_unknown_kwarg"
     cont = Controller(Sink(), ready_timeout=0.3, **{unknown: True})
     expectedre = r"__init__.. got an unexpected keyword argument '" + unknown + r"'"
     try:
         with pytest.raises(TypeError, match=expectedre):
             cont.start()
         assert cont.smtpd is None
         assert isinstance(cont._thread_exception, TypeError)
     finally:
         cont.stop()
예제 #14
0
 def test_socket_error_default(self):
     contr1 = Controller(Sink())
     contr2 = Controller(Sink())
     expectedre = r"error while attempting to bind on address"
     try:
         with pytest.raises(socket.error, match=expectedre):
             contr1.start()
             contr2.start()
     finally:
         contr2.stop()
         contr1.stop()
예제 #15
0
def smtp_server():
    '''
    Provides an asynchronous SMTP server to test mail delivering functionalities. 
    
    Returns a controller that stores the received messages.
    '''
    handler = TestSMTPHandler()
    controller = Controller(handler)
    controller.start()
    yield handler
    controller.stop()
예제 #16
0
 def test_unknown_args_inkwargs(self, silence_event_loop_closed: bool):
     unknown = "this_is_an_unknown_kwarg"
     cont = Controller(Sink(),
                       ready_timeout=0.3,
                       server_kwargs={unknown: True})
     expectedre = r"__init__.. got an unexpected keyword argument '" + unknown + r"'"
     try:
         with pytest.raises(TypeError, match=expectedre):
             cont.start()
         assert cont.smtpd is None
     finally:
         cont.stop()
예제 #17
0
 def test_factory_none(self, mocker: MockFixture,
                       silence_event_loop_closed):
     # Hypothetical situation where factory() did not raise an Exception
     # but returned None instead
     mocker.patch("aiosmtpd.controller.SMTP", return_value=None)
     cont = Controller(Sink(), ready_timeout=0.3)
     expectedre = r"factory\(\) returned None"
     try:
         with pytest.raises(RuntimeError, match=expectedre):
             cont.start()
         assert cont.smtpd is None
     finally:
         cont.stop()
예제 #18
0
파일: inbox3.py 프로젝트: zegevlier/inbox3
    def serve(self, port=None, address=None, log_level=logbook.INFO):
        """Serves the SMTP server on the given port and address."""

        port = port or self.port
        address = address or self.address

        controller = Controller(InboxServerHandler(self.collator), hostname=address, port=port)

        try:
            controller.start()
            controller._thread.join()
        except KeyboardInterrupt:
        finally:
            controller.stop()
예제 #19
0
class DummyMailServer(ContextManager['DummyMailServer']):
    """dummy mail server for testing
    """
    def authenticator(self, _unused_server: SMTP, _unused_session: Session,
                      _unused_envelope: Envelope, mechanism: str,
                      login_data: Tuple[bytes, bytes]) -> AuthResult:

        if mechanism not in ('LOGIN', 'PLAIN'):
            return AuthResult(success=False, handled=False)
        if not isinstance(login_data, LoginPassword):  # type: ignore
            return AuthResult(success=False, handled=False)

        username = login_data.login.decode()  # type: ignore
        password = login_data.password.decode()  # type: ignore

        if username != self._user or password != self._password:
            return AuthResult(success=False, handled=False)

        return AuthResult(success=True)

    def __enter__(self) -> 'DummyMailServer':
        # skipcq: PYL-W0201
        self._controller = Controller(
            handler=Debugging(),
            tls_context=self._tsl_context,
            # otherwise mail-client have to decode data manually (split by \r\n)
            decode_data=True,
            # require starttls from client for authentication
            require_starttls=True,
            port=self._port,
            authenticator=self.authenticator)
        self._controller.start()
        return self

    def __exit__(self, _unused_exc_type: Optional[Type[BaseException]],
                 _unused_exc_value: Optional[BaseException],
                 _unused_traceback: Optional[TracebackType]) -> Optional[bool]:
        if not self._controller:
            return None

        self._controller.stop()  # type: ignore
        return False

    def __init__(self, user: str, password: str, port: int) -> None:
        self._user = user
        self._password = password
        self._port = port
        self._tsl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
        self._tsl_context.check_hostname = False
        self._tsl_context.load_cert_chain(certfile=MAIL_CERT, keyfile=MAIL_KEY)
예제 #20
0
class CapturingAiosmtpdServer:
    """An async SMTP server / context manager for testing RPC effects."""
    def __init__(self):
        self.messages = []
        self.handler = CapturingAiosmtpdHandler(context=self)
        self.controller = Controller(handler=self.handler,
                                     hostname="localhost",
                                     port=10025)

    def __enter__(self):
        self.controller.start()
        return self

    def __exit__(self, *exc):
        self.controller.stop()
예제 #21
0
class CapturingAiosmtpdServer:
    """An async SMTP server / context manager for testing RPC effects."""

    def __init__(self):
        self.messages = []
        self.handler = CapturingAiosmtpdHandler(context=self)
        self.controller = Controller(
            handler=self.handler, hostname="localhost", port=10025)

    def __enter__(self):
        self.controller.start()
        return self

    def __exit__(self, *exc):
        self.controller.stop()
예제 #22
0
    def handle(self, *args, **kwargs):
        controller = Controller(
            IncomingMailHandler(),
            hostname=settings.INCOMING_TASK_MAIL_HOSTNAME,
            port=settings.INCOMING_TASK_MAIL_PORT,
        )

        self.stdout.write(
            f"Listening for incoming mail on {controller.hostname}:{controller.port}"
        )

        try:
            controller.start()
            while True:
                time.sleep(0.1)
        except KeyboardInterrupt:
            controller.stop()
예제 #23
0
    def serve(self, port=None, address=None, log_level=logbook.INFO):
        """Serves the SMTP server on the given port and address."""
        logbook.StreamHandler(sys.stdout, level=log_level).push_application()

        port = port or self.port
        address = address or self.address

        log.info('Starting SMTP server at {0}:{1}'.format(address, port))
        controller = Controller(InboxServerHandler(self.collator),
                                hostname=address,
                                port=port)

        try:
            controller.start()
            controller._thread.join()
        except KeyboardInterrupt:
            log.info('Cleaning up')
        finally:
            controller.stop()
예제 #24
0
async def server(*, config: Config) -> t.AsyncIterator[Queue[Message]]:
    """Manage the LMTP server's lifetime.

    Args:
        config: application configuration.

    Yields:
        Queue of incoming mail.
    """
    msg_queue: Queue[Message] = Queue()
    controller = Controller(
        handler=LmtpHandler(config=config, queue=msg_queue),
        hostname=config.lmtp_host,
        port=config.lmtp_port,
    )
    controller.start()
    logger.info(f"listening on {config.lmtp_host}:{config.lmtp_port}")
    yield msg_queue
    controller.stop()
예제 #25
0
파일: cli.py 프로젝트: livestalker/smtpdev
def main(smtp_host, smtp_port, web_host, web_port, develop, debug, maildir):
    if debug:
        logging.basicConfig(level=logging.DEBUG)
    else:
        logging.basicConfig(level=logging.INFO)

    logger.info("SMTP server is running on %s:%s", smtp_host, smtp_port)
    logger.info("Web server is running on %s:%s", web_host, web_port)

    if develop:
        logger.info("Running in developer mode")

    dir_context = TemporaryDirectory if maildir is None else lambda: nullcontext(
        maildir)

    with dir_context() as maildir_path:
        maildir_path = pathlib.Path(maildir_path)
        maildir_path.mkdir(parents=True, exist_ok=True)

        logger.info("Mail directory: %s", maildir_path)

        config = Configuration(
            smtp_host=smtp_host,
            smtp_port=smtp_port,
            web_host=web_host,
            web_port=web_port,
            develop=develop,
            debug=debug,
        )

        maildir = Maildir(maildir_path / "maildir")
        mailbox = MailboxHandler(maildir_path / "maildir")

        controller = Controller(mailbox,
                                hostname=config.smtp_host,
                                port=config.smtp_port)
        web_server = WebServer(config, maildir)
        mailbox.register_message_observer(web_server)

        controller.start()
        web_server.start()
        controller.stop()
예제 #26
0
def email_catcher():
    class TestHandler:
        received_mail = []

        async def handle_RCPT(self, server, session, envelope, address, rcpt_options):
            if not address.endswith("@example.com"):
                return "550 not relaying to that domain"
            envelope.rcpt_tos.append(address)
            return "250 OK"

        async def handle_DATA(self, server, session, envelope):
            self.received_mail.append(envelope)
            return "250 Message accepted for delivery"

    controller = Controller(TestHandler(), hostname="localhost", port=8025)
    controller.start()
    try:
        yield controller
    finally:
        controller.stop()
예제 #27
0
def start(reload: 'Make server autoreload (Dev only)' = False, ):
    """ Start byemail """

    settings.init_settings()

    controller = Controller(smtpserver.MSGHandler(), **settings.SMTP_CONF)
    controller.start()

    asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
    loop = asyncio.get_event_loop()

    app = httpserver.get_app()
    server = app.create_server(**settings.HTTP_CONF)
    asyncio.ensure_future(server)

    try:
        print("Server started on %s:%d" %
              (controller.hostname, controller.port))
        loop.run_forever()
    except KeyboardInterrupt:
        print("Stopping")

    controller.stop()
예제 #28
0
    def test_noexc_smtpd_missing(self, mocker, silence_event_loop_closed):
        # Hypothetical situation where factory() failed but no
        # Exception was generated.
        cont = Controller(Sink())

        def hijacker(*args, **kwargs):
            cont._thread_exception = None
            # Must still return an (unmocked) _FakeServer to prevent a whole bunch
            # of messy exceptions, although they doesn't affect the test at all.
            return _FakeServer(cont.loop)

        mocker.patch("aiosmtpd.controller._FakeServer", side_effect=hijacker)
        mocker.patch("aiosmtpd.controller.SMTP",
                     side_effect=RuntimeError("Simulated Failure"))

        expectedre = r"Unknown Error, failed to init SMTP server"
        try:
            with pytest.raises(RuntimeError, match=expectedre):
                cont.start()
            assert cont.smtpd is None
            assert cont._thread_exception is None
        finally:
            cont.stop()
def smtp_messages():
    message_q: Queue = Queue()
    ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
    ssl_context.load_cert_chain(THIS_DIR / "test_cert.pem",
                                THIS_DIR / "test_key.pem")

    class SMTPHandler:
        async def handle_DATA(self, _server, session, envelope):
            peer = session.peer
            mail_from = envelope.mail_from
            rcpt_tos = envelope.rcpt_tos
            data = envelope.content  # type: bytes
            msg = SMTPMessage(peer, mail_from, rcpt_tos, data)
            message_q.put(msg)
            return "250 OK"

    def smtp_authenticator(_server, _session, _envelope, mechanism, auth_data):
        auth_failed = smtp.AuthResult(success=False, handled=False)
        if mechanism != "LOGIN":
            return auth_failed
        username = auth_data.login.decode("utf-8")
        password = auth_data.password.decode("utf-8")
        if username != config.smtp_user or password != config.smtp_pass:
            return auth_failed
        return smtp.AuthResult(success=True)

    controller = SMTPController(SMTPHandler(),
                                hostname=SMTP_TEST_SERVER_HOST,
                                port=SMTP_TEST_SERVER_PORT,
                                auth_required=True,
                                authenticator=smtp_authenticator,
                                tls_context=ssl_context)
    controller.start()
    try:
        yield queue_consumer(message_q)
    finally:
        controller.stop()
예제 #30
0
    def test_real_mail_aiosmtpd(self):
        """ Test sending messages with a real-world SMTPD server """
        if aiosmtpd is None:
            self.skipTest('aiosmtpd not available')

        # Start an smtp server
        mail_handler = StashingHandler()
        controller = Controller(mail_handler,
                                loop=None,
                                hostname='localhost',
                                port=self.smtpd_port)
        controller.start()

        # Give it time to settle
        sleep(0.5)

        # Initialize a Postman
        postman = Postman(
            '*****@*****.**',
            NoLoginSMTP('localhost', self.smtpd_port, None, None))

        # Send messages
        with postman.connect() as c:
            # Send plaintext message
            msg = Message(['*****@*****.**'], 'Subject', 'HTML message')
            c.sendmail(msg)

            # Send unicode message
            msg = Message(['*****@*****.**'], u'Håkon', u'Håkon')
            c.sendmail(msg)

        # Done
        controller.stop()

        # Test
        self.assertEqual(len(mail_handler.mail), 2)
예제 #31
0
        log.info("Quitting...")
        self.quit = True


if __name__ == "__main__":
    log.debug(", ".join([f"{k}={v}" for k, v in config.items()]))

    # If there's a dir called log - set up a filehandler
    if os.path.exists("log"):
        log.info("Setting up a filehandler")
        fh = logging.FileHandler("log/emqtt.log")
        fh.setFormatter(formatter)
        log.addHandler(fh)

    loop = asyncio.get_event_loop()
    c = Controller(
        handler=EMQTTHandler(loop),
        loop=loop,
        hostname="0.0.0.0",
        port=config["SMTP_PORT"],
    )
    c.start()
    log.info("Running")
    try:
        while not c.handler.quit:
            time.sleep(0.5)
        c.stop()
    except:
        c.stop()
        raise
예제 #32
0
class AiosmtpdServerManager:
    def __init__(self, handler: AIOHandler, auth: bool = False) -> None:
        self.handler = handler
        self.auth = auth

    def __enter__(self) -> Controller:
        auth_kwargs = {}
        if self.auth:
            auth_kwargs = {
                "auth_required": True,
                "authenticator": authenticator,
            }

        if EmailSettings.connection_security in [
                ConnectionSecurity.STARTTLS,
                ConnectionSecurity.SSLTLS,
        ]:
            ssl_context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
            ssl_context.load_default_certs(purpose=ssl.Purpose.SERVER_AUTH)
            ssl_context.load_cert_chain("cert.pem", "key.pem")
            ssl_context.check_hostname = False
            ssl_context.verify_mode = ssl.VerifyMode.CERT_NONE
            if EmailSettings.connection_security == ConnectionSecurity.SSLTLS:
                # This is a hack: The aiosmtpd library does not issue AUTH in EHLO, if not starttls is used.
                # For other methods (SSL/TLS and NONE) setting auth_require_tls allows AUTH. The intention is to
                # allow AUTH before TLS (which is ok for NONE), but a hack for SSL/TLS since we have an
                # encrypted connection
                if self.auth:
                    auth_kwargs["auth_require_tls"] = False
                self.controller = Controller(
                    self.handler,
                    EmailSettings.host,
                    EmailSettings.port,
                    server_hostname="127.0.0.1",
                    ssl_context=ssl_context,
                    **auth_kwargs,  # type: ignore
                )
            else:
                self.controller = Controller(
                    self.handler,
                    EmailSettings.host,
                    EmailSettings.port,
                    server_hostname="127.0.0.1",
                    require_starttls=True,
                    tls_context=ssl_context,
                    **auth_kwargs,  # type: ignore
                )
        else:
            if self.auth:
                auth_kwargs["auth_require_tls"] = False
            self.controller = Controller(
                self.handler,
                EmailSettings.host,
                EmailSettings.port,
                **auth_kwargs  # type: ignore
            )

        self.controller.start()
        return self.controller

    def __exit__(
        self,
        exc_type: Optional[Type[BaseException]],
        exc_value: Optional[BaseException],
        exc_traceback: Optional[TracebackType],
    ) -> None:
        if self.controller.loop.is_running():
            self.controller.stop(no_assert=True)
예제 #33
0
class CustomHandler:
    async def handle_RCPT(self, server, session, envelope, address,
                          rcpt_options):
        envelope.rcpt_tos.append(address)
        return '250 OK'

    async def handle_DATA(self, server, session, envelope):
        print('Message from', envelope.mail_from)
        print('Message for', envelope.rcpt_tos)
        print('Message data:\n')
        print(envelope.content.decode('utf8', errors='replace'))
        return '250 Message accepted for delivery'


controller = Controller(CustomHandler(), None, '0.0.0.0', 8025)

ts = time.time()
st = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')
print('Running SMTP Server ', st)

controller.start()

loop = asyncio.get_event_loop()
try:
    loop.run_forever()
finally:
    loop.run_until_complete(loop.shutdown_asyncgens())
    controller.stop()
    loop.close()