docs: def data(self, message):
          """
          Send LMTP DATA command and process the server response.
  
          The server response is stored as a list of dicts in
          <DspamClient>.results, keyed on the recipient name(s). Depending
          on the server return data, different formats are available:
          * LMTP mode    -- Dict containing 'accepted', a bool indicating
                            that the message was handed to the server.
          * Summary mode -- Dict containing 'username', 'result',
                            'classification', 'probability', 'confidence'
                            and 'signature'.
          * Stdout mode  -- Dict containing 'result' and 'message', the
                            complete message payload including added headers.
  
          The return data is always parsed and stored, independent of its format.
          If you requested a regular LMTP response, but the server
          responded with an DLMTP summary, the summary is still stored in
          <DspamClient>.results, and you will need to check the result format
          yourself and decide whether that was acceptable for your use case.
          This is due to the fact that it's possible to configure the server to
          return non LMTP responses, even when in LMTP mode (see dspam.conf:
          ServerParameters).
  
          Note: while processing response data in stdout mode, it's not possible
          to relate the returned messages to a specific recipient, when multiple
          recipients were specified in rcptto(). There is no guarantee
          that the message stored in <DspamClient>.results['foo'] actually
          belongs to the recipient 'foo'. If this relationship needs to be
          guaranteed, send each message with a single recipient in rcptto().
  
          args:
          message -- The full message payload to pass to the server.
  
          """
          self._send('DATA\r\n')
          resp = self._read()
          if not resp.startswith('354'):
              raise DspamClientError(
                  'Unexpected server response at DATA: ' + resp)
  
          # Send message payload
          for line in message.split('\n'):
              if line == '.':
                  # Dot stuffing
                  line = '..'
              self._send(line)
  
          # Send end-of-data
          self._send('.\r\n')
  
          # Depending on server configuration, several responses are possible:
          # * Standard LMTP response code, once for each recipient:
          #   250 2.6.0 <bar> Message accepted for delivery
          # * Summary response (--deliver=summary), once for each recipient:
          #   X-DSPAM-Result: bar; result="Spam"; class="Spam"; \
          #     probability=1.0000; confidence=0.85; \
          #     signature=50c50c0f315636261418125
          #   (after the last summary line, a single dot is sent)
          # * Stdout response (--delivery=stdout), once for each recipient:
          #   X-Daemon-Classification: INNOCENT
          #   <complete mail body>
          #
          # Note that when an unknown recipient is passed in, DSPAM will simply
          #   deliver the message (dspam.conf: (Un)TrustedDeliveryAgent,
          #   DeliveryHost) unaltered and unfiltered. The response for unknown
          #   recipients will still be something indicating 'accepted'.
  
          peek = self._peek(24)
          if peek.startswith('250'):
              # Response is LTMP formatted
              regex = re.compile('250 \d\.\d\.\d <([^>]+)>')
              finished = False
              while not finished:
                  resp = self._read()
                  match = regex.match(resp)
                  if not match:
                      raise DspamClientError(
                          'Unexpected server response at END-OF-DATA: ' + resp)
                  rcpt = match.group(1)
                  self.results[rcpt] = {'accepted': True}
                  logger.debug(
                      'Message accepted for recipient {} in LMTP mode'.format(
                          rcpt))
                  if len(self.results) == len(self._recipients):
                      finished = True
  
          elif peek.startswith('X-DSPAM-Result:'):
              # Response is in summary format
              regex = re.compile('X-DSPAM-Result: ([^;]+); result="(\w+)"; '
                                 'class="(\w+)"; probability=([\d\.]+); '
                                 'confidence=([\d\.]+); signature=([\w,/]+)')
              finished = False
              while not finished:
                  resp = self._read()
                  match = regex.match(resp)
                  if not match:
                      raise DspamClientError(
                          'Unexpected server response at END-OF-DATA: ' + resp)
                  rcpt = match.group(1)
  
                  # map results to their DSPAM classification result names
                  fields = ('user', 'result', 'class',
                            'probability', 'confidence', 'signature')
                  self.results[rcpt] = dict(zip(fields, match.groups()))
                  if self.results[rcpt]['signature'] == 'N/A':
                      del(self.results[rcpt]['signature'])
  
                  logger.debug(
                      'Message handled for recipient {} in DLMTP summary mode, '
                      'result is {}'.format(rcpt, match.group(2)))
                  if len(self.results) == len(self._recipients):
                      # we received responses for all accepted recipients
                      finished = True
              # read final dot
              resp = self._read()
              if resp != '.':
                  raise DspamClientError(
                      'Unexpected server response at END-OF-DATA: ' + resp)
  
          elif peek.startswith('X-Daemon-Classification:'):
              # Response is in stdout format
              finished = False
              message = ''
              while not finished:
                  resp = self._read()
                  if resp.startswith('X-Daemon-Classification:'):
                      if message != '':
                          # A new message body starts, store the previous one
                          rcpt = self._recipients.pop(0)
                          self.results[rcpt] = {
                              'result': result,
                              'message': message
                          }
                          logger.debug(
                              'Message handled for recipient {} in DLMTP '
                              'stdout mode, result is {}, message body '
                              'is {} chars'.format(rcpt, result, len(message)))
                          message = ''
                      # Remember next result
                      result = resp[25:]
  
                  elif resp == '.':
                      # A single dot can signal end-of-data, or might be just
                      #   regular mail data.
                      self._socket.setblocking(False)
                      try:
                          # If _peek() succeeds, we did not reach end-of-data yet
                          #   so it was message content.
                          peek = self._peek(1)
                          message = message + '\r\n' + resp
                      except socket.error:
                          # reached end-of-data, store message and finish
                          finished = True
                          rcpt = self._recipients.pop(0)
                          # strip final newline
                          message = message[0:-2]
                          self.results[rcpt] = {
                              'result': result,
                              'message': message
                          }
                          logger.debug(
                              'Message accepted for recipient {} in DLMTP '
                              'stdout mode, result is {}, message body '
                              'is {} chars'.format(rcpt, result, len(message)))
  
                      self._socket.setblocking(True)
  
                  else:
                      # regular message data
                      if message == '':
                          message = resp
                      else:
                          message = message + '\r\n' + resp
  
          else:
              raise DspamClientError(
                  'Unexpected server response at END-OF-DATA: ' + resp)