I want to send a signed mail with smime with the module cryptography
. But all my mail programms can't detect the subject if I sign the mail. If I don't sign the mail it shows the subject.
import smtplib
from email.header import Header
from email.mime.multipart import MIMEMultipart
from email.mime.image import MIMEImage
from email.mime.text import MIMEText
from email.utils import formataddr, formatdate
from cryptography import x509
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.serialization import pkcs7
from jinja2 import Template
email_from = "root@wikipedia.org"
email_to = "user@wikipedia.org"
message = MIMEMultipart("mixed", protocol="application/x-pkcs7-signature", micalg="sha-256")
message["Subject"] = Header("mail subject", "utf-8").encode()
message["From"] = formataddr(("Sender", email_from))
message["To"] = email_to
message["Date"] = formatdate(localtime=True)
message["Auto-Submitted"] = "auto-generated"
html_template = (
Path(EMAIL_TEMPLATES_DIR) / f"{template}.html"
).read_text()
html_j2_template = Template(html_template)
html = html_j2_template.render(environment)
message.attach(MIMEText(html, "html"))
ca_cert = open(CA_CERT_PATH, "rb").read()
ca_key = open(CA_KEY_PATH, "rb").read()
cert = x509.load_pem_x509_certificate(ca_cert)
key = serialization.load_pem_private_key(ca_key, None)
options = [pkcs7.PKCS7Options.DetachedSignature]
signed_text = (
pkcs7.PKCS7SignatureBuilder()
.set_data(message.as_bytes())
.add_signer(cert, key, hashes.SHA256())
.sign(serialization.Encoding.SMIME, options)
)
with smtplib.SMTP() as server:
server.connect(25)
server.sendmail(email_from, email_to, signed_text)
And here the version with the module email
for python>=3.6
.
import smtplib
from email.headerregistry import Address
from email.message import EmailMessage
from email.utils import formatdate
from cryptography import x509
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.serialization import pkcs7
from jinja2 import Template
email_from = "root@wikipedia.org"
email_to = "user@wikipedia.org"
message = EmailMessage()
message["Subject"] = subject_template
message["From"] = Address("Sender", email_from)
message["To"] = Address("Receiver", email_to)
message["Date"] = formatdate(localtime=True)
message["Auto-Submitted"] = "auto-generated"
html_template = (
Path(EMAIL_TEMPLATES_DIR) / f"{template}.html"
).read_text()
html_j2_template = Template(html_template)
html = html_j2_template.render(environment)
message.set_content(html, subtype="html")
ca_cert = open(CA_CERT_PATH, "rb").read()
ca_key = open(CA_KEY_PATH, "rb").read()
cert = x509.load_pem_x509_certificate(ca_cert)
key = serialization.load_pem_private_key(ca_key, None)
options = [pkcs7.PKCS7Options.DetachedSignature]
signed_text = (
pkcs7.PKCS7SignatureBuilder()
.set_data(message.as_bytes())
.add_signer(cert, key, hashes.SHA256())
.sign(serialization.Encoding.SMIME, options)
)
with smtplib.SMTP() as server:
server.connect(25)
server.sendmail(email_from, email_to, signed_text)
The solution is a dirty hack, but it works for the moment
import smtplib
from email.header import Header
from email.message import EmailMessage
from cryptography import x509
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.serialization import pkcs7
message = EmailMessage()
message["Subject"] = subject_template
message["From"] = Address("Sender", email_from)
message["To"] = Address("Receiver", email_to)
message["Date"] = formatdate(localtime=True)
message["Auto-Submitted"] = "auto-generated"
body = "This a plain text body!"
message.set_content(body)
ca_cert = open("cert.pem", "rb").read()
ca_key = open("key.pem", "rb").read()
cert = x509.load_pem_x509_certificate(ca_cert)
key = serialization.load_pem_private_key(ca_key, None)
options = [pkcs7.PKCS7Options.DetachedSignature]
signed_text = (
pkcs7.PKCS7SignatureBuilder()
.set_data(message.as_bytes())
.add_signer(cert, key, hashes.SHA256())
.sign(serialization.Encoding.SMIME, options)
)
header = (
f"""From: {Address("Sender", email_from)}\n"""
f"""To: {Address("Receiver", email_to)}\n"""
f"""Date: {formatdate(localtime=True)}\n"""
f"""Auto-Submitted: auto-generated\n"""
f"""Subject: {Header("Mail Subject", "utf-8").encode()}\n"""
)
signed_text = header.encode() + signed_text
with smtplib.SMTP() as server:
server.connect(port=25)
server.sendmail(from_addr, to_addr, signed_text)