docs: async def sendmail(
          self,
          sender: str,
          recipients: RecipientsType,
          message: Union[str, bytes],
          mail_options: Iterable[str] = None,
          rcpt_options: Iterable[str] = None,
          timeout: DefaultNumType = _default,
      ) -> SendmailResponseType:
          """
          This command performs an entire mail transaction.
  
          The arguments are:
              - sender: The address sending this mail.
              - recipients: A list of addresses to send this mail to.  A bare
                  string will be treated as a list with 1 address.
              - message: The message string to send.
              - mail_options: List of options (such as ESMTP 8bitmime) for the
                  MAIL command.
              - rcpt_options: List of options (such as DSN commands) for all the
                  RCPT commands.
  
          message must be a string containing characters in the ASCII range.
          The string is encoded to bytes using the ascii codec, and lone \\\\r
          and \\\\n characters are converted to \\\\r\\\\n characters.
  
          If there has been no previous HELO or EHLO command this session, this
          method tries EHLO first.
  
          This method will return normally if the mail is accepted for at least
          one recipient.  It returns a tuple consisting of:
  
              - an error dictionary, with one entry for each recipient that was
                  refused.  Each entry contains a tuple of the SMTP error code
                  and the accompanying error message sent by the server.
              - the message sent by the server in response to the DATA command
                  (often containing a message id)
  
          Example:
  
               >>> loop = asyncio.get_event_loop()
               >>> smtp = aiosmtplib.SMTP(hostname="127.0.0.1", port=1025)
               >>> loop.run_until_complete(smtp.connect())
               (220, ...)
               >>> recipients = ["one@one.org", "two@two.org", "3@three.org"]
               >>> message = "From: Me@my.org\\nSubject: testing\\nHello World"
               >>> send_coro = smtp.sendmail("me@my.org", recipients, message)
               >>> loop.run_until_complete(send_coro)
               ({}, 'OK')
               >>> loop.run_until_complete(smtp.quit())
               (221, Bye)
  
          In the above example, the message was accepted for delivery for all
          three addresses. If delivery had been only successful to two
          of the three addresses, and one was rejected, the response would look
          something like::
  
              (
                  {"nobody@three.org": (550, "User unknown")},
                  "Written safely to disk. #902487694.289148.12219.",
              )
  
  
          If delivery is not successful to any addresses,
          :exc:`.SMTPRecipientsRefused` is raised.
  
          If :exc:`.SMTPResponseException` is raised by this method, we try to
          send an RSET command to reset the server envelope automatically for
          the next attempt.
  
          :raises SMTPRecipientsRefused: delivery to all recipients failed
          :raises SMTPResponseException: on invalid response
          """
          if isinstance(recipients, str):
              recipients = [recipients]
          else:
              recipients = list(recipients)
  
          if mail_options is None:
              mail_options = []
          else:
              mail_options = list(mail_options)
  
          if rcpt_options is None:
              rcpt_options = []
          else:
              rcpt_options = list(rcpt_options)
  
          async with self._sendmail_lock:
              if self.supports_extension("size"):
                  size_option = "size={}".format(len(message))
                  mail_options.append(size_option)
  
              try:
                  await self.mail(sender, options=mail_options, timeout=timeout)
                  recipient_errors = await self._send_recipients(
                      recipients, options=rcpt_options, timeout=timeout
                  )
                  response = await self.data(message, timeout=timeout)
              except (SMTPResponseException, SMTPRecipientsRefused) as exc:
                  # If we got an error, reset the envelope.
                  try:
                      await self.rset(timeout=timeout)
                  except (ConnectionError, SMTPResponseException):
                      # If we're disconnected on the reset, or we get a bad
                      # status, don't raise that as it's confusing
                      pass
                  raise exc
  
          return recipient_errors, response.message