def __init__(self, sender=None, recipients=None, headers=None, message=None): #: Sending address of the message. self.sender = sender #: List of recipient addresses of the message. self.recipients = recipients or [] #: :class:`email.message.Message` object for accessing and modifying #: message headers. self.headers = headers #: String of message data, not including headers. check_argtype(message, bytes, 'message', or_none=True) self.message = message #: Dictionary of information about the client that sent the message. #: Utilized keys include: #: #: - ``ip``: The IP of the client. #: - ``host``: The reverse-lookup of the client IP. #: - ``name``: The client name, as given by its ``EHLO`` or #: alternative. #: - ``protocol``: The protocol used by the client, generally a variant #: of ``"SMTP"``. #: - ``auth``: The name the client successfully authenticated with, or #: ``None``. self.client = {} #: Hostname of the :mod:`slimta` server that received the message. self.receiver = None #: Timestamp when the message was received. self.timestamp = None
def raw_send(self, data): check_argtype(data, six.binary_type, 'data') try: self.socket.sendall(data) except socket_error as e: if e.errno == ECONNRESET: raise ConnectionLost() raise log.send(self.socket, data)
def _process_part(self, part): """ :type part: bytes """ check_argtype(part, six.binary_type, 'part') part_len = len(part) i = 0 if part_len > 0 and part[0:1] == b'.': yield b'.' while i < part_len: index = part.find(b'\n.', i) if index == -1: yield part if i == 0 else part[i:] i = part_len else: yield part[i:index + 2] yield b'.' i = index + 2
def _process_part(self, part): """ :type part: bytes """ check_argtype(part, six.binary_type, 'part') part_len = len(part) i = 0 if part_len > 0 and part[0:1] == b'.': yield b'.' while i < part_len: index = part.find(b'\n.', i) if index == -1: yield part if i == 0 else part[i:] i = part_len else: yield part[i:index+2] yield b'.' i = index+2
def __init__(self, code=None, message=None, command=None): self.command = command #: Holds the reply code, which can only be set to a string containing #: three digits. check_argtype(code, six.string_types, 'code', or_none=True) self.code = code #: Holds the ENHANCEDSTATUSCODES_ string. This property is usually set #: automatically by the ``message`` property. self.enhanced_status_code = None #: Gets and sets the reply message. If you set this property with an #: ENHANCEDSTATUSCODES_ string prefixed, that string will be pulled out #: and set in the ``enhanced_status_code``. check_argtype(message, six.string_types, 'message', or_none=True) self.message = message #: Boolean defining whether a newline should be sent before the reply, #: which is useful for asynchronous replies such as timeouts. self.newline_first = False
def parse(self, data): """Parses the given string to populate the :attr:`headers` and :attr:`message` attributes. :param data: The complete message, headers and message body. :type data: :py:obj:`bytes` """ check_argtype(data, bytes, 'data') match = re.search(_HEADER_BOUNDARY, data) if not match: header_data = data payload = b'' else: header_data = data[:match.end(0)] payload = data[match.end(0):] header_data_decoded = utf8only_decode(header_data) self.headers = Parser().parsestr(header_data_decoded, True) self.message = self.headers.get_payload().encode('ascii') + payload self.headers.set_payload('')