156 lines
5.2 KiB
Python
156 lines
5.2 KiB
Python
|
# coding: utf-8
|
||
|
import asyncio
|
||
|
import time
|
||
|
import re
|
||
|
import sys
|
||
|
import os
|
||
|
import aiosmtplib
|
||
|
import traceback
|
||
|
from aiosmtpd.controller import Controller
|
||
|
from sqlalchemy.future import select
|
||
|
from .model import db, update_mx, update_a, FQDN, MXRecord, ARecord, IPV4Addr, Direccion, Destinatario, Carta
|
||
|
from .registro import log
|
||
|
|
||
|
from .smtpd import ilabHandler
|
||
|
from .registro import log
|
||
|
from .resolver import updateDNS
|
||
|
|
||
|
smtprelayport = '10025'
|
||
|
bindip = '0.0.0.0'
|
||
|
|
||
|
if not os.environ.get('SMTP_HOSTNAME'):
|
||
|
banner_hostname = 'midominio.cl'
|
||
|
else:
|
||
|
banner_hostname = os.environ.get('SMTP_HOSTNAME')
|
||
|
|
||
|
|
||
|
async def enviarCorreosDominio(dominioid):
|
||
|
valido = int(time.time())
|
||
|
try:
|
||
|
await log.debug('Enviando correos dominio {}'.format(dominioid))
|
||
|
indices = []
|
||
|
servidores = await db.execute(select(ARecord).where(ARecord.fqdnid.in_(select(MXRecord.fqdnmxid).where(MXRecord.fqdnid==dominioid, MXRecord.validohasta>valido))))
|
||
|
|
||
|
for arecordx in servidores.scalars():
|
||
|
indice = arecordx.enviados + arecordx.errores*20
|
||
|
indices.append((indice, arecordx))
|
||
|
|
||
|
# await log.debug('El dominio tiene un total de {} servidores'.format(len(indices)))
|
||
|
|
||
|
for _, arecord in sorted(indices, key=lambda tup: tup[0]):
|
||
|
ipresult = await db.execute(select(IPV4Addr).where(IPV4Addr.id==arecord.ipv4id))
|
||
|
dbdireccion = ipresult.scalar_one_or_none()
|
||
|
try:
|
||
|
conectado = False
|
||
|
try:
|
||
|
smtp = aiosmtplib.SMTP(hostname=str(dbdireccion.ipaddr), use_tls=True, validate_certs=False, timeout=10)
|
||
|
await smtp.connect()
|
||
|
conectado = True
|
||
|
except Exception as e:
|
||
|
conectado = False
|
||
|
await log.debug('Error al conectar al servidor use_tls: {}'.format(e))
|
||
|
|
||
|
if conectado == False:
|
||
|
try:
|
||
|
smtp = aiosmtplib.SMTP(hostname=str(dbdireccion.ipaddr), start_tls=True, validate_certs=False, timeout=10)
|
||
|
await smtp.connect()
|
||
|
conectado = True
|
||
|
except Exception as e:
|
||
|
conectado = False
|
||
|
await log.debug('Error al conectar al servidor start_tls: {}'.format(e))
|
||
|
if conectado == False:
|
||
|
try:
|
||
|
smtp = aiosmtplib.SMTP(hostname=str(dbdireccion.ipaddr), timeout=10)
|
||
|
await smtp.connect()
|
||
|
await smtp.helo(banner_hostname)
|
||
|
conectado = True
|
||
|
except Exception as e:
|
||
|
conectado = False
|
||
|
await log.debug('Error al conectar al servidor {}: {}'.format(dbdireccion.ipaddr, e))
|
||
|
continue
|
||
|
|
||
|
await log.debug('Conectado a SMTP({}) '.format(dbdireccion.ipaddr))
|
||
|
rcartas = await db.execute(select(Carta).join(Destinatario).join(Direccion).where(Direccion.dominioid==dominioid, Destinatario.enviado==0))
|
||
|
for carta in rcartas.scalars():
|
||
|
# await log.debug('Componiendo Carta {} '.format(carta.id))
|
||
|
|
||
|
rteresult = await db.execute(select(Direccion).where(Direccion.id==carta.remitenteid))
|
||
|
remitente = rteresult.scalar_one_or_none()
|
||
|
rcpt_to = []
|
||
|
|
||
|
rdest = await db.execute(select(Destinatario).join(Direccion).where(Direccion.dominioid==dominioid, Destinatario.cartaid==carta.id, Destinatario.enviado==0))
|
||
|
for destinatario in rdest.scalars():
|
||
|
destresult = await db.execute(select(Direccion).where(Direccion.id==destinatario.direccionid))
|
||
|
rcpt_to.append( str(destresult.scalar_one_or_none().direccion) )
|
||
|
destinatario.intentos = destinatario.intentos + 1
|
||
|
await db.commit()
|
||
|
rdest = await db.execute(select(Destinatario).join(Direccion).where(Direccion.dominioid==dominioid, Destinatario.cartaid==carta.id, Destinatario.enviado==0))
|
||
|
|
||
|
await log.info("Carta Rte '{}' => Destinatarios '{}' ".format(remitente.direccion, ', '.join(rcpt_to)))
|
||
|
try:
|
||
|
await smtp.sendmail(str(remitente.direccion), rcpt_to, carta.contenido)
|
||
|
for destinatario in rdest.scalars():
|
||
|
destinatario.enviado = 1
|
||
|
|
||
|
arecord.enviados = arecord.enviados + 1
|
||
|
except Exception as e:
|
||
|
await log.warning('Error al enviar el correo {}'.format(e))
|
||
|
|
||
|
for destinatario in rdest.scalars():
|
||
|
if destinatario.intentos > 2:
|
||
|
destinatario.enviado = 2
|
||
|
|
||
|
arecord.errores = arecord.errores + 1
|
||
|
|
||
|
await db.commit()
|
||
|
await smtp.quit()
|
||
|
return True
|
||
|
|
||
|
|
||
|
except Exception as e:
|
||
|
await log.warning('Error en el servidor {}'.format(e))
|
||
|
arecord.errores = arecord.errores + 1
|
||
|
await db.commit()
|
||
|
|
||
|
except:
|
||
|
await log.warning('Traceback {}'.format(traceback.format_exc()))
|
||
|
return False
|
||
|
|
||
|
async def enviaCorreos():
|
||
|
|
||
|
try:
|
||
|
rdestino = await db.execute(select(Destinatario).join(Direccion).join(FQDN).where(Destinatario.enviado==0).distinct(FQDN.id))
|
||
|
tareas = []
|
||
|
for destinatario in rdestino.scalars():
|
||
|
result = await db.execute(select(Direccion).where(Direccion.id==destinatario.direccionid))
|
||
|
dbemail = result.scalar_one_or_none()
|
||
|
await enviarCorreosDominio(dbemail.dominioid)
|
||
|
|
||
|
except:
|
||
|
await log.error('Traceback {}'.format(traceback.format_exc()))
|
||
|
|
||
|
|
||
|
def create_async_smtp_server():
|
||
|
handler = ilabHandler()
|
||
|
|
||
|
controller = Controller(handler, hostname=bindip, port=smtprelayport)
|
||
|
|
||
|
return controller
|
||
|
|
||
|
async def pre_process():
|
||
|
try:
|
||
|
if await updateDNS():
|
||
|
return True
|
||
|
except:
|
||
|
pass
|
||
|
|
||
|
return False
|
||
|
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
mayordomo = create_async_smtp_server()
|
||
|
|
||
|
mayordomo.start()
|
||
|
input(u'SMTP server (Mayordomo) esta operativo')
|
||
|
mayordomo.stop()
|