Sending email without keyfile (only certfile) using Python smtplib

前端 未结 2 853
萌比男神i
萌比男神i 2021-01-14 16:31

Trying to send email with a certificate file using the following script:

import smtplib

client = smtplib.SMTP(myhost, myport)
client.ehlo()
client.starttls(         


        
相关标签:
2条回答
  • 2021-01-14 17:09

    Here's a monkey-patch taken from this page:

    class SMTPExt(smtplib.SMTP):
        """
        This class extends smtplib.SMTP and overrides the starttls method
        allowing extra parameters and forwarding them to ssl.wrap_socket.
        """
    
        def starttls(self, keyfile=None, certfile=None, **kwargs):
            self.ehlo_or_helo_if_needed()
            if not self.has_extn("starttls"):
                raise SMTPException("STARTTLS extension not supported by server.")
            (resp, reply) = self.docmd("STARTTLS")
            if resp == 220:
                self.sock = ssl.wrap_socket(self.sock, keyfile, certfile, **kwargs)
                self.file = SSLFakeFile(self.sock)
                # RFC 3207:
                # The client MUST discard any knowledge obtained from
                # the server, such as the list of SMTP service extensions,
                # which was not obtained from the TLS negotiation itself.
                self.helo_resp = None
                self.ehlo_resp = None
                self.esmtp_features = {}
                self.does_esmtp = 0
            return (resp, reply)
    

    Using the root cert from requests

    0 讨论(0)
  • 2021-01-14 17:19

    There are two ways to use SSL/TLS: client authenticated and "basic" where the client is unauthenticated. In client authenticated connections, the both the server and the client send a certificate to the other. In "basic" only the server does.

    If you pass neither a certificate nor a keyfile, smtplib will use a basic connection, where the client is authenticated.

    If you use a certificate, it will be used for a client authenticated connection. In that case, the server will demand that the client shows it owns the certificate by signing a handshake message. For the client to be able to do that it also needs the private key, which can be either in the certificate file or as a separate keyfile.

    Long story short, if you want to use a client certificate, you must also use a key. If not, you can just leave both empty.


    OTOH, maybe you have a server certificate file or CA list you want to use with the connection?

    In that case you need to pass it to ssl.wrap_socket in the ca_certs parameter. Since you use Python 2.6 there's no easy way to do that with smtplib (Python 3.3+ has a context argument to starttls).

    How to solve this depends on your application. For example, if you do not need ssl for anything else, a hackish solution would be to monkey-patch ssl.wrap_socket with one that provides your ca_cert (as well as cert_reqs=CERT_REQUIRED, likely).

    A more full blown solution would be to extend smtplib.SMTP with your own variant that does allow passing in those parameters.

    0 讨论(0)
提交回复
热议问题