import ipaddress
import logging
import re
-from collections import OrderedDict
+from collections.abc import Sequence
# Third party modules
-from fb_tools.common import is_sequence
from fb_tools.common import pp
from fb_tools.errors import InvalidMailAddressError
from fb_tools.mailaddress import MailAddress
-from fb_tools.mailaddress import MailAddressList
from fb_tools.obj import FbGenericBaseObject
# Own modules
_ = XLATOR.gettext
ngettext = XLATOR.ngettext
-__version__ = '0.7.0'
+__version__ = '0.7.1'
LOG = logging.getLogger(__name__)
@rtype: dict
"""
if exportable:
- res = OrderedDict()
+ res = {}
else:
res = super(SmtpAction, self).as_dict(short=short)
)
# -------------------------------------------------------------------------
- def __init__(self, to_addresses=[], **kwargs):
+ def __init__(self, smtp_actions=None, **kwargs):
"""Initialize this object."""
for attr in self.attributes:
priv_name = '_' + attr
setattr(self, priv_name, None)
- self.to_addresses = MailAddressList()
- if to_addresses:
- self.set_to_addresses(to_addresses)
+ self.smtp_actions = []
+ if smtp_actions:
+ self.set_smtp_actions(smtp_actions)
for attr in kwargs.keys():
if attr not in self.attributes:
setattr(self, attr, kwargs[attr])
# -------------------------------------------------------------------------
- def set_to_addresses(self, addresses):
- """Set the array with all TO addresses of the mail after address resolution."""
- self.to_addresses = []
- if addresses is None:
+ def set_smtp_actions(self, smtp_actions):
+ """Set the array with all SMTP actions of Postfix after address resolution."""
+ self.smtp_actions = []
+ if smtp_actions is None:
return
- if isinstance(addresses, MailAddressList):
- self.to_addresses = copy.copy(addresses)
- return
-
- if not is_sequence(addresses):
- addresses = [addresses]
+ if not isinstance(smtp_actions, (Sequence, tuple)):
+ smtp_actions = [smtp_actions]
- for addr in addresses:
- self.to_addresses.append(addr)
+ for action in smtp_actions:
+ self.add_smtp_action(action)
# -------------------------------------------------------------------------
- def add_to_address(self, address):
- """Append the given mail address to the list of TO addresses."""
- self.to_addresses.append(address)
+ def add_smtp_action(self, action):
+ """Append the given SmtpAction to the list of TO smtp_actions."""
+ if action is None:
+ msg = _('You may not append a None value as a SmtpAction to the list smtp_actions.')
+ raise TypeError(msg)
+
+ if isinstance(action, SmtpAction):
+ self.smtp_actions.append(action)
+ return
+
+ if isinstance(action, dict):
+ smtp_action = SmtpAction(**action)
+ self.smtp_actions.append(smtp_action)
+ return
+
+ msg = _('Wrong type {c!r} for creating a {w} object from: {a!r}').format(
+ c=action.__class__.__name__, w='SmtpAction', a=action)
+ raise TypeError(msg)
# -----------------------------------------------------------
@property
@rtype: dict
"""
if exportable:
- res = OrderedDict()
+ res = {}
else:
res = super(PostfixLogchainInfo, self).as_dict(short=short)
# Catch all
res[attrib] = value
+ res['smtp_actions'] = None
if exportable:
- res['to_addresses'] = None
- if self.to_addresses:
- res['to_addresses'] = self.to_addresses.as_list(as_str=True)
+ if self.smtp_actions:
+ res['smtp_actions'] = []
+ for action in self.smtp_actions:
+ res['smtp_actions'].append(action.as_dict(exportable=True))
else:
- res['to_addresses'] = copy.copy(self.to_addresses)
+ res['smtp_actions'] = []
+ for action in self.smtp_actions:
+ res['smtp_actions'].append(action.as_dict(short=short))
# Non init properties
if not exportable:
re_postfix_id = re.compile(r'^(?P<id>[0-9a-f]+):\s+', re.IGNORECASE)
re_tls_line = re.compile(r'Trusted\s+TLS\s+connection\s+established', re.IGNORECASE)
+ re_host_said = re.compile(r'i^\s*host\s+\S+\s+said: \d', re.IGNORECASE)
maillog = self.logfile
if 'MAILLOG' in os.environ:
continue
m_id = re_postfix_id.match(message)
+ postfix_id = None
if m_id:
- # postfix_id = m_id['id'].upper()
+ postfix_id = m_id['id'].upper()
message = re_postfix_id.sub('', message)
+ if not postfix_id:
+ continue
+
+ if re_host_said.match(message):
+ continue
+
i += 1
action = SmtpAction.from_log_entry(
timestamp=timestamp, pid=pid, message=message,
'@sparkassen-finanzportal.de>?='
)
+ smtp_action1 = {
+ 'date': '2024-03-15T03:46:59.821790+00:00',
+ 'delay_total': 1.5,
+ 'dsn': '2.6.0',
+ 'message': (
+ '250 2.6.0 <=?UTF-8?Q?<175f6f376cac747b4f23caa8de25ec41@example-customer01.de>?=> '
+ '[InternalId=9740985831629, Hostname=AS4P15MB1453.EURP195.PROD.OUTLOOK.COM] 30253 '
+ 'bytes in 0.177, 166.044 KB/sec Queued mail for delivery -> 250 2.1.5'),
+ 'relay': 'mailprovider08.com[104.47.14.33]:25',
+ 'remote_id': '9740985831629',
+ 'smtp_pid': '7621',
+ 'status': 'sent',
+ 'time_before_queue': 0.44,
+ 'time_conn_setup': 0.17,
+ 'time_in_queue': 0.1,
+ 'time_xmission': 0.8,
+ 'to_address': 'ahlam_lar@mailprovider09.com',
+ }
+ smtp_action2 = {
+ 'date': '2024-03-15T03:47:05.123456+00:00',
+ 'delay_total': 2.8,
+ 'dsn': '2.0.0',
+ 'message': '250 OK id=1rkxb6-00037T-0f',
+ 'relay': 'webmail.vgw.de[80.151.72.120]:25',
+ 'remote_id': '1rkxb6-00037T-0f',
+ 'smtp_pid': '20679',
+ 'status': 'sent',
+ 'time_before_queue': 0.44,
+ 'time_conn_setup': 0.36,
+ 'time_in_queue': 0.09,
+ 'time_xmission': 1.9,
+ 'to_address': 'arik@vgw.de',
+ }
+
chain = PostfixLogchainInfo(
client_host='mail.uhu-banane.de',
client_addr='188.34.187.246',
tls_cipher='ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)',
size=12345,
nr_rcpt=1,
+ smtp_actions=[smtp_action1],
)
- chain.add_to_address('frank.brehm@pixelpark.com')
- chain.add_to_address('thomas.dalichow@pixelpark.com')
+ chain.add_smtp_action(smtp_action2)
+
LOG.debug('PostfixLogchainInfo %r: {!r}'.format(chain))
LOG.debug('PostfixLogchainInfo %s:\n{}'.format(chain))
LOG.debug('PostfixLogchainInfo as_dict():\n{}'.format(pp(chain.as_dict())))