如何在Python的exchangelib中添加自定义头发送手动加密S/MIME邮件
Hey there! Since exchangelib doesn’t include built-in support for S/MIME encryption, manually constructing your encrypted message with the required headers is the right approach. Here’s a step-by-step guide to make this work:
1. Prepare Your Encrypted S/MIME Content
First, you’ll need to generate the base64-encoded PKCS#7 encrypted content (the smime.p7m data). You mentioned you already know how to do this with OpenSSL—make sure this encrypted content includes everything you want in the email (body + any attachments). For context, if you’re including attachments, you’ll first build a standard MIME message with those attachments, then encrypt that entire message using the recipient’s public key to get your final base64 string.
2. Use Exchangelib’s mime_content to Control the Full MIME Message
Instead of letting exchangelib auto-generate the email structure, you can pass a complete MIME-formatted string directly using the mime_content attribute of the Message object. This lets you define all custom headers exactly as you need them.
Here’s a code example:
from exchangelib import Account, Message, Mailbox # Replace these with your actual details encrypted_smime_content = "YOUR_BASE64_ENCODED_PKCS7_DATA_HERE" your_email = "your-email@example.com" recipient_email = "recipient@example.com" exchange_username = "your-exchange-username" exchange_password = "your-exchange-password" # Connect to your Exchange account (use your existing connection logic) account = Account( primary_smtp_address=your_email, credentials=(exchange_username, exchange_password), autodiscover=True, access_type="delegate" ) # Build the full MIME message string with all required headers mime_message = f"""MIME-Version: 1.0 Content-Type: application/pkcs7-mime; name="smime.p7m"; smime-type=enveloped-data Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="smime.p7m" Content-Description: S/MIME Encrypted Message {encrypted_smime_content} """ # Create the message and set the MIME content msg = Message( account=account, subject="S/MIME Encrypted Test Email" ) msg.mime_content = mime_message.encode("utf-8") # Add recipients msg.to_recipients = [Mailbox(email_address=recipient_email)] # Send the email msg.send()
3. Bonus: Building and Encrypting a Message with Attachments
If you need to include attachments in the encrypted email, first build a standard MIME message with those attachments, then encrypt that entire message. Here’s how you can do that with Python’s built-in email module and OpenSSL:
from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.mime.image import MIMEImage import subprocess import tempfile # Step 1: Build a regular MIME message with body and attachments plain_msg = MIMEMultipart() plain_msg["Subject"] = "Original Message Content" plain_msg["From"] = your_email plain_msg["To"] = recipient_email # Add plain text body body = MIMEText("This is the unencrypted body text", "plain") plain_msg.attach(body) # Add an image attachment (adjust for your file type) with open("your-image.jpg", "rb") as f: img_attachment = MIMEImage(f.read()) img_attachment.add_header("Content-Disposition", "attachment", filename="your-image.jpg") plain_msg.attach(img_attachment) # Step 2: Write the plain message to a temp file for OpenSSL with tempfile.NamedTemporaryFile(mode="w", delete=False) as f: f.write(plain_msg.as_string()) temp_in_path = f.name with tempfile.NamedTemporaryFile(mode="r", delete=False) as f: temp_out_path = f.name # Step 3: Encrypt the message with OpenSSL (use recipient's public cert) subprocess.run( [ "openssl", "smime", "-encrypt", "-in", temp_in_path, "-out", temp_out_path, "-outform", "PEM", "-certfile", "recipient-public-cert.pem" ], check=True ) # Step 4: Extract the base64 content (strip PEM headers) with open(temp_out_path, "r") as f: encrypted_content = f.read().replace("-----BEGIN PKCS7-----", "").replace("-----END PKCS7-----", "").strip() # Now use this encrypted_content in the first code example to send the email
Key Notes
- Using
mime_contentgives you full control over the email’s headers and content, so exchangelib won’t override or auto-generate any of the S/MIME-specific headers you need. - Make sure you encrypt the entire MIME message (body + attachments) before passing it to exchangelib—don’t encrypt just the body text if you have attachments.
内容的提问来源于stack exchange,提问作者Breakfast Serial

