def METHOD_NAME(attributes):
    """Sends an email using an SMTP relay host
    Generates an email from the bootstrap process and routes it through a
    smarthost.  The parameters value expects a dictionary with the
    following values in order for this function to work properly.
    ::
        {
            'smarthost':   <hostname of smarthost>,
            'sender':      <from email address>
            'receivers':   [ <array of recipients to send email to> ],
            'subject':     <subject line of the message>,
            'body':        <the message body>,
            'attachments': [ <array of files to attach> ],
            'commands':    [ <array of commands to run and attach> ]
        }
    The required fields for this function are smarthost, sender, and
    receivers. All other fields are optional.
    This action is dual-supervisor compatible.
    Args:
        attributes (list): list of attributes; use attributes.get(<ATTRIBUTE_NAME>)
                            to read attribute values
        node (internal): attributes.get('NODE') API: see documentation
        smarthost: hostname of smarthos>,
        sender: from email addres>
        receivers: [ <array of recipients to send email to> ]
        subject: subject line of the message
        body: the message body
        attachments: [ <array of files to attach> ]
        commands: [ <array of commands to run and attach> ]
    Example:
        ::
            -
              action: send_mail
              attributes:
                  smarthost: smtp.example.com
                  from: noreply@example.com
                  subject: This is a test message from a switch in ZTP
                  receivers:
                      bob@exmple.com
                      helen@example.com
                  body: Please see the attached 'show version'
                  commands: show version
    """
    node = attributes.get("NODE")
    smarthost = attributes.get("smarthost")
    if not smarthost:
        raise RuntimeError("Missing attribute('smarthost')")
    sender = attributes.get("sender")
    if not sender:
        raise RuntimeError("Missing attribute('sender')")
    receivers = attributes.get("receivers")
    if not receivers:
        raise RuntimeError("Missing attribute('receivers')")
    msg = MIMEMultipart.MIMEMultipart()
    msg["From"] = sender
    msg["To"] = COMMASPACE.join(receivers)
    msg["Date"] = formatdate(localtime=True)
    msg["Subject"] = attributes.get("subject") or "ZTP Bootstrap"
    body = attributes.get("body", "empty-body")
    attachments = attributes.get("attachments", [])
    commands = attributes.get("commands", [])
    attributes.get("NODE").log_msg("Running commands: {}".format(str(commands)))
    if commands:
        body += "\nThe output from the following commmands have been added as attachments:"
        for command in commands:
            filename = run_command(command, node)
            attachments.append(filename)
            body += "\n\t* {} ({})".format(command, filename)
    attributes.get("NODE").log_msg("Collecting attachments: {}".format(str(attachments)))
    if attachments:
        for filename in attachments:
            if os.path.exists(filename):
                filename = filename.strip()
                part = MIMEBase.MIMEBase("application", "octet-stream")
                with io.open(filename, "rb", encoding="utf8") as fd:
                    part.set_payload(fd.read())
                Encoders.encode_base64(part)
                part.add_header(
                    "Content-Disposition",
                    "attachment; filename='{}'".format(os.path.basename(filename)),
                )
                attributes.get("NODE").log_msg("Attaching {}".format(filename))
                msg.attach(part)
    msg.attach(MIMEText(body))
    attributes.get("NODE").log_msg("Sending email using smarthost {}".format(smarthost))
    send_message(smarthost, sender, receivers, msg)