Skip to content Skip to sidebar Skip to footer

Sending Email Without Keyfile (only Certfile) Using Python Smtplib

Trying to send email with a certificate file using the following script: import smtplib client = smtplib.SMTP(myhost, myport) client.ehlo() client.starttls(certfile=mycertfile) cl

Solution 1:

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.


Solution 2:

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


Post a Comment for "Sending Email Without Keyfile (only Certfile) Using Python Smtplib"