experimental mail transport
This commit is contained in:
parent
e43d4837c3
commit
7cee8a3cc2
6 changed files with 141 additions and 18 deletions
|
@ -31,6 +31,8 @@ DEBUG = True
|
|||
|
||||
ALLOWED_HOSTS = [os.getenv('HTTP_HOST', 'localhost')]
|
||||
|
||||
MAIL_DOMAIN = os.getenv('MAIL_DOMAIN', 'localhost')
|
||||
|
||||
SYSTEM3_VERSION = "0.0.0-dev.0"
|
||||
|
||||
# Application definition
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
#!/usr/bin/env python3
|
||||
import asyncio
|
||||
import logging
|
||||
import os
|
||||
from abc import ABCMeta
|
||||
|
||||
import uvicorn
|
||||
from aiosmtpd.controller import Controller, UnixSocketController
|
||||
from aiosmtpd.controller import Controller, UnixSocketController, BaseController, UnixSocketMixin
|
||||
from aiosmtpd.lmtp import LMTP
|
||||
|
||||
|
||||
|
@ -26,7 +28,8 @@ async def handle_echo(reader, writer):
|
|||
|
||||
class ExampleHandler:
|
||||
async def handle_RCPT(self, server, session, envelope, address, rcpt_options):
|
||||
if not address.endswith('@example.com'):
|
||||
from core.settings import MAIL_DOMAIN
|
||||
if not address.endswith('@' + MAIL_DOMAIN):
|
||||
return '550 not relaying to that domain'
|
||||
envelope.rcpt_tos.append(address)
|
||||
return '250 OK'
|
||||
|
@ -47,17 +50,39 @@ class LTMPController(Controller):
|
|||
return LMTP(self.handler)
|
||||
|
||||
|
||||
class UnixSocketLMTPController(UnixSocketController):
|
||||
class BaseAsyncController(BaseController, metaclass=ABCMeta):
|
||||
def __init__(
|
||||
self,
|
||||
handler,
|
||||
loop,
|
||||
**SMTP_parameters,
|
||||
):
|
||||
super().__init__(
|
||||
handler,
|
||||
loop,
|
||||
**SMTP_parameters,
|
||||
)
|
||||
|
||||
def serve(self):
|
||||
return self._create_server()
|
||||
|
||||
|
||||
class UnixSocketLMTPController(UnixSocketMixin, BaseAsyncController):
|
||||
def factory(self):
|
||||
return LMTP(self.handler)
|
||||
|
||||
def _trigger_server(self): # pragma: no-unixsock
|
||||
# Prevent confusion on which _trigger_server() to invoke.
|
||||
# Or so LGTM.com claimed
|
||||
UnixSocketMixin._trigger_server(self)
|
||||
|
||||
|
||||
class UvicornServer(uvicorn.Server):
|
||||
def install_signal_handlers(self):
|
||||
pass
|
||||
|
||||
|
||||
async def web():
|
||||
async def web(loop):
|
||||
log_config = uvicorn.config.LOGGING_CONFIG
|
||||
log_config["handlers"]["default"] = {"class": "logging.FileHandler", "filename": "web.log", "formatter": "default"}
|
||||
log_config["handlers"]["access"] = {"class": "logging.FileHandler", "filename": "web-access.log",
|
||||
|
@ -67,8 +92,10 @@ async def web():
|
|||
await server.serve()
|
||||
|
||||
|
||||
async def tcp():
|
||||
log = logging.getLogger('test')
|
||||
async def tcp(loop):
|
||||
log = logging.getLogger('test.log')
|
||||
log.addHandler(logging.FileHandler('test.log'))
|
||||
log.setLevel(logging.DEBUG)
|
||||
log.info("Starting TCP server")
|
||||
server = await asyncio.start_unix_server(handle_echo, path='test.sock')
|
||||
|
||||
|
@ -80,11 +107,24 @@ async def tcp():
|
|||
log.info("TCP done")
|
||||
|
||||
|
||||
async def lmtp():
|
||||
log = logging.getLogger('lmtp')
|
||||
async def lmtp(loop):
|
||||
import grp
|
||||
log = logging.getLogger('mail.log')
|
||||
log.addHandler(logging.FileHandler('mail.log'))
|
||||
log.setLevel(logging.WARNING)
|
||||
log.info("Starting LMTP server")
|
||||
cont = UnixSocketLMTPController(ExampleHandler(), unix_socket='lmtp.sock')
|
||||
cont.start()
|
||||
server = await UnixSocketLMTPController(ExampleHandler(), unix_socket='lmtp.sock', loop=loop).serve()
|
||||
|
||||
addrs = ', '.join(str(sock.getsockname()) for sock in server.sockets)
|
||||
log.info(f'Serving on {addrs}')
|
||||
|
||||
os.chmod('lmtp.sock', 0o775)
|
||||
current_uid = os.getuid()
|
||||
posix_gid = grp.getgrnam('postfix').gr_gid
|
||||
os.chown('lmtp.sock', current_uid, posix_gid)
|
||||
|
||||
async with server:
|
||||
await server.serve_forever()
|
||||
log.info("LMTP done")
|
||||
|
||||
|
||||
|
@ -104,18 +144,18 @@ def main():
|
|||
import sdnotify
|
||||
import signal
|
||||
import setproctitle
|
||||
import os
|
||||
setproctitle.setproctitle("c3lf-sys3")
|
||||
logging.basicConfig(filename='server.log', level=logging.DEBUG, encoding='utf-8')
|
||||
logging.basicConfig(filename='test.log', level=logging.DEBUG, encoding='utf-8')
|
||||
logging.basicConfig(filename='lmtp.log', level=logging.DEBUG, encoding='utf-8')
|
||||
log = logging.getLogger()
|
||||
log = logging.getLogger('server.log')
|
||||
log.addHandler(logging.FileHandler('server.log'))
|
||||
log.setLevel(logging.DEBUG)
|
||||
log.info("Starting server")
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.add_signal_handler(signal.SIGTERM, lambda: asyncio.create_task(shutdown(signal.SIGTERM, loop)))
|
||||
loop.add_signal_handler(signal.SIGINT, lambda: asyncio.create_task(shutdown(signal.SIGINT, loop)))
|
||||
loop.create_task(web())
|
||||
loop.create_task(tcp())
|
||||
loop.create_task(lmtp())
|
||||
loop.create_task(web(loop))
|
||||
loop.create_task(tcp(loop))
|
||||
loop.create_task(lmtp(loop))
|
||||
n = sdnotify.SystemdNotifier()
|
||||
n.notify("READY=1")
|
||||
log.info("Server ready")
|
||||
|
@ -123,8 +163,13 @@ def main():
|
|||
loop.run_forever()
|
||||
finally:
|
||||
loop.close()
|
||||
os.remove("lmtp.sock")
|
||||
os.remove("test.sock")
|
||||
os.remove("web.sock")
|
||||
logging.info("Server stopped")
|
||||
|
||||
logging.shutdown()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
@ -8,6 +8,7 @@ c3lf-nodes:
|
|||
git_branch: master
|
||||
git_repo: <git_repo_url>
|
||||
db_password: <db_password>
|
||||
mail_domain: <mail_domain>
|
||||
main_email: <main_email>
|
||||
legacy_api_user: <legacy_api_user>
|
||||
legacy_api_password: <legacy_api_password>
|
|
@ -275,3 +275,27 @@
|
|||
name: c3lf-sys3
|
||||
state: started
|
||||
enabled: yes
|
||||
|
||||
- name: add postfix to www-data group
|
||||
user:
|
||||
name: postfix
|
||||
groups: www-data
|
||||
append: yes
|
||||
notify:
|
||||
- restart postfix
|
||||
|
||||
- name: add custom transport config
|
||||
lineinfile:
|
||||
path: /etc/postfix/master.cf
|
||||
line: "c3lf-sys3 unix - n n - - lmtp"
|
||||
state: present
|
||||
create: yes
|
||||
notify:
|
||||
- restart postfix
|
||||
|
||||
- name: configure postfix
|
||||
template:
|
||||
src: templates/postfix.cf.j2
|
||||
dest: /etc/postfix/main.cf
|
||||
notify:
|
||||
- restart postfix
|
|
@ -4,6 +4,7 @@ DB_NAME=c3lf_sys3
|
|||
DB_USER=c3lf_sys3
|
||||
DB_PASSWORD={{ db_password }}
|
||||
HTTP_HOST={{ web_domain }}
|
||||
MAIL_DOMAIN={{ mail_domain }}
|
||||
LEGACY_API_USER={{ legacy_api_user }}
|
||||
LEGACY_API_PASSWORD={{ legacy_api_password }}
|
||||
MEDIA_ROOT=/var/www/c3lf-sys3/userfiles
|
||||
|
|
50
deploy/ansible/playbooks/templates/postfix.cf.j2
Normal file
50
deploy/ansible/playbooks/templates/postfix.cf.j2
Normal file
|
@ -0,0 +1,50 @@
|
|||
# See /usr/share/postfix/main.cf.dist for a commented, more complete version
|
||||
|
||||
|
||||
# Debian specific: Specifying a file name will cause the first
|
||||
# line of that file to be used as the name. The Debian default
|
||||
# is /etc/mailname.
|
||||
#myorigin = /etc/mailname
|
||||
|
||||
smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU)
|
||||
biff = no
|
||||
|
||||
# appending .domain is the MUA's job.
|
||||
append_dot_mydomain = no
|
||||
|
||||
readme_directory = no
|
||||
|
||||
# See http://www.postfix.org/COMPATIBILITY_README.html -- default to 3.6 on
|
||||
# fresh installs.
|
||||
compatibility_level = 3.6
|
||||
|
||||
# TLS parameters
|
||||
smtp_use_tls = yes
|
||||
smtp_force_tls = yes
|
||||
smtpd_use_tls = yes
|
||||
smtpd_tls_cert_file=/etc/letsencrypt/live/{{ web_domain }}/fullchain.pem;
|
||||
smtpd_tls_key_file=/etc/letsencrypt/live/{{ web_domain }}/privkey.pem;
|
||||
smtpd_tls_security_level=may
|
||||
|
||||
smtp_tls_CApath=/etc/ssl/certs
|
||||
smtp_tls_security_level=may
|
||||
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
|
||||
|
||||
|
||||
smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
|
||||
myhostname = polaris.c3lf.de
|
||||
alias_maps = hash:/etc/aliases
|
||||
alias_database = hash:/etc/aliases
|
||||
myorigin = /etc/mailname
|
||||
mydestination = $myhostname, , localhost
|
||||
relayhost = firefly.lab.or.it
|
||||
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
|
||||
mailbox_size_limit = 0
|
||||
recipient_delimiter = +
|
||||
inet_interfaces = all
|
||||
inet_protocols = all
|
||||
|
||||
maillog_file = /var/log/mail.log
|
||||
|
||||
virtual_mailbox_domains = {{ mail_domain }}
|
||||
virtual_transport=c3lf-sys3:unix:/var/www/c3lf-sys3/lmtp.sock
|
Loading…
Reference in a new issue