EDIT: This issue resolved itself as mysteriously as it began. Simply hoping it doesn't crop up again in the future.
I have a small python script that emails out a comic strip once a day to a handful of email addresses. Recently, one person on my list told me that the images are no longer displayed. I got the source of the email from her Gmail account, and for some reason the base-64 encoded section for the image in blank.
I have no idea why this is happening, and why it's happening to only one person. I get an SPF soft-fail in the Gmail headers, but I doubt that's causing it (that should happen to all the Gmail users on my list.) I don't even know what to Google to start troubleshooting this issue.
Faulty Email Source {censored items in curly braces}:
Delivered-To: {recipient}#gmail.com
Received: by 2002:ac2:555e:0:0:0:0:0 with SMTP id l30csp2647742lfk;
Sun, 22 Mar 2020 02:12:09 -0700 (PDT)
X-Google-Smtp-Source: ADFU+vt1SopHnbnPh0tuHjbA/v3RMASeIKMyk35ZdIXqQHBr2LmtG11vVo6cI8XXxUf/emCJQjqb
X-Received: by 2002:a92:25d6:: with SMTP id l205mr14876228ill.35.1584868329096;
Sun, 22 Mar 2020 02:12:09 -0700 (PDT)
ARC-Seal: i=1; a=rsa-sha256; t=1584868329; cv=none;
d=google.com; s=arc-20160816;
b=o1VVDgxlMMWGRPy041qJS6LfA1LWjEB6+cbp768sLmMaOk7Q+qbCpAg0Mydf3pg/yu
N3Nfh0Zv7vUdS6sapH0LzmcCG6YVBC/fkGboFuUeVJgVw24CcY8e1ofkMmIkWardIQie
bNfAnebSMmIhmZ6UTrR79ggRhUglFx6EdAzNYdmpyRCxewK3/SN5JjdfW6KUQsgjQXU5
PvJQEZZrt07eKjzq2kpNVobWBj8rOvVGpYc+fqNDOircTIF5ZTI3JIbCEkNvvEyAmZOW
AK68xVtSpaYfInnJ0++dPkS9DhuH777f/yMz6Z0X26MjnoxiIovyYSNPfzZLdjpnC/CI
G4nQ==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816;
h=date:message-id:to:from:subject:mime-version;
bh=nXPNVg7/Z2G2UDLCbHAibUHl0oCh4sJ6yhHsm9HpP+Y=;
b=Vl5At9J4nLzeREzg93sHypB2XO/vbNHAtRj4apOzQZHLg0XbjD3Hxv6t9+yzFn8thS
pFnPRPCOOgyY+mp+8hTQrT5TaIlEcNC9Ay1x25X27wqcr0iBjw9xpTvjvFo1pX7jNK7E
DvUZpdSoSmas32U0zT8DH1+jX5zX/8Ydr7aTOkVLPX6umVuyl2RNlW+mLZrPnCMkiH0Z
jeTc88LMiczwsVwo2qsoKPDjFah+xTD7J+zqnuHr6IuMS3+s9t7dy4sbKRwlcxP4n2z4
ZXjJbQpEEfOec36EF89By4ZHNHxLmDx/DZvPA5nv10emet1Omki9w2HF3hcaAijZDL2l
jb1g==
ARC-Authentication-Results: i=1; mx.google.com;
spf=softfail (google.com: domain of transitioning {sender}#{my-domain} does not designate {my-ip-address} as permitted sender) smtp.mailfrom={sender}#{my-domain}
Return-Path: <{sender}#{my-domain}>
Received: from {my-domain} ([{my-ip-address}])
by mx.google.com with ESMTP id 141si8443110ile.78.2020.03.22.02.12.03
for <{recipient}#gmail.com>;
Sun, 22 Mar 2020 02:12:09 -0700 (PDT)
Received-SPF: softfail (google.com: domain of transitioning {sender}#{my-domain} does not designate {my-ip-address} as permitted sender) client-ip={my-ip-address};
Authentication-Results: mx.google.com;
spf=softfail (google.com: domain of transitioning {sender}#{my-domain} does not designate {my-ip-address} as permitted sender) smtp.mailfrom={sender}#{my-domain}
Received: from {my-domain} (localhost [IPv6:::1]) by {my-domain} (Postfix) with SMTP id BEFC13C00DD for <{recipient}#gmail.com>; Sun, 22 Mar 2020 05:12:02 -0400 (EDT)
Content-Type: multipart/related; boundary="===============0513549325=="
MIME-Version: 1.0
Subject: Calvin and Hobbes of the day
From: {sender}#{my-domain}
To: {recipient}#gmail.com
Message-Id: <20200322091202.BEFC13C00DD#{my-domain}>
Date: Sun, 22 Mar 2020 05:12:02 -0400 (EDT)
--===============0513549325==
Content-Type: multipart/alternative; boundary="===============1139914447=="
MIME-Version: 1.0
--===============1139914447==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Calvin and Hobbes of the day email. Image not displayed for techical reasons. To unsubscribe, send an email to {sender}#{my-domain} with the subject "Unsubscribe please". You may briefly continue to recieve emails until the system processes your request.
--===============1139914447==
Content-Type: text/html; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
<img src="cid:30cbc076bf26fa38547141665a3874fc0bdc91b550d5b9523fbf033cd64d0d8b"><p>This Calvin and Hobbes was originally published on Tuesday, March 22, 1994. Enjoy!</p><p style="font-family:serif;text-size:9pt;">To unsubscribe, send an email to {sender}#{my-domain} with the subject "Unsubscribe please". You may briefly continue to recieve emails until the system processes your request.</p>
--===============1139914447==--
--===============0513549325==
Content-Type: image/gif
MIME-Version: 1.0
Content-Transfer-Encoding: base64
Content-ID: <30cbc076bf26fa38547141665a3874fc0bdc91b550d5b9523fbf033cd64d0d8b>
--===============0513549325==--
Example of an email that displayed properly (also sent to a Gmail account):
Delivered-To: {recipient2}#gmail.com
Received: by 2002:ac0:945c:0:0:0:0:0 with SMTP id j28csp4283482imj;
Sun, 22 Mar 2020 02:12:06 -0700 (PDT)
X-Google-Smtp-Source: ADFU+vsBj6iMIZiI5aEUI+EaVIoyR/pGQUdx46SNDNiosv8OoI8WLTCvAYmWxdVSsUEGEThEY3kc
X-Received: by 2002:a92:4090:: with SMTP id d16mr1882262ill.200.1584868326631;
Sun, 22 Mar 2020 02:12:06 -0700 (PDT)
ARC-Seal: i=1; a=rsa-sha256; t=1584868326; cv=none;
d=google.com; s=arc-20160816;
b=o85d2nyxnlrJBxjPjbEIK+iBEUzip5+8qaw3AP2sf1oWPSHGUjyKSJMM9ya0nTgByo
wn+hN60zGz/y23w7k6yp3V0gy94rP+qiMRn87bgahsdF6SOH6n2gDn1aYPFNZPCLRrgU
UI+a3aX/qdDtw03LL8A9mj+v+TCvEyntddxWjiU2UHuXT88GLOPAwmt0PwH/wQp52nRV
V4jnKFbGQU7A2FkzJccW1T6GgzoXejmXOcHi4z7emm4TGHNv4FxlPl/bna2X8dFo+8N5
mHh7+ADWyy9wHATPJqPEtTXuBoE8Bri9n20IMKaPWKzpoasb5bFV14kA+cRkh/CckHr7
3Vxw==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816;
h=date:message-id:to:from:subject:mime-version;
bh=tcCxyEZafImccO+owloPVRqzcCuM+m7me+VxZuISjGU=;
b=e5DjPTX5Ia11uM7bKBRA+vGqkGlsYdJuv6Mxio7xhRtcxqBxxxyIZ80ludnCvWR/j8
/B1qmGG6ZynxVlv7GTPOF4yP6qWhE2sycKf3yQ5MYZXLFmZMRSW0kcj/fjoKvd3BOOBV
8DlZUNVvfNujZpm+7sdNHhT+xAU8EY1+9+b3R6GDEyDJzKrIgXclX9yVHsH91DDa5AC8
WOUBH4ZrOZ0Zn5bvpSLOomqhGI4J2gZeb41zj8RjjuwPOE9LR5fmDCxNn+ajeBAbnJPG
Ihl3jkrnuiJWcigsn38ctPw6inWglsK3dxKBTeXbrWHHeRtu9kHZnL1l9vpl93BM/LN9
6jgQ==
ARC-Authentication-Results: i=1; mx.google.com;
spf=softfail (google.com: domain of transitioning {sender}#{my-domain} does not designate {my-ip-address} as permitted sender) smtp.mailfrom={sender}#{my-domain}
Return-Path: <{sender}#{my-domain}>
Received: from {my-domain} ([{my-ip-address}])
by mx.google.com with ESMTP id k2si9367254jap.23.2020.03.22.02.12.03
for <{recipient2}#gmail.com>;
Sun, 22 Mar 2020 02:12:06 -0700 (PDT)
Received-SPF: softfail (google.com: domain of transitioning {sender}#{my-domain} does not designate {my-ip-address} as permitted sender) client-ip={my-ip-address};
Authentication-Results: mx.google.com;
spf=softfail (google.com: domain of transitioning {sender}#{my-domain} does not designate {my-ip-address} as permitted sender) smtp.mailfrom={sender}#{my-domain}
Received: from {my-domain} (localhost [IPv6:::1])
by {my-domain} (Postfix) with SMTP id 98FA73C00A7
for <{recipient2}#gmail.com>; Sun, 22 Mar 2020 05:12:02 -0400 (EDT)
Content-Type: multipart/related; boundary="===============1535165371=="
MIME-Version: 1.0
Subject: Calvin and Hobbes of the day
From: {sender}#{my-domain}
To: {recipient2}#gmail.com
Message-Id: <20200322091202.98FA73C00A7#{my-domain}>
Date: Sun, 22 Mar 2020 05:12:02 -0400 (EDT)
This is a multi-part message in MIME format.
--===============1535165371==
Content-Type: multipart/alternative; boundary="===============1545014324=="
MIME-Version: 1.0
--===============1545014324==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Calvin and Hobbes of the day email. Image not displayed for techical reasons. To unsubscribe, send an email to {sender}#{my-domain} with the subject "Unsubscribe please". You may briefly continue to recieve emails until the system processes your request.
--===============1545014324==
Content-Type: text/html; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
<img src="cid:30cbc076bf26fa38547141665a3874fc0bdc91b550d5b9523fbf033cd64d0d8b"><p>This Calvin and Hobbes was originally published on Tuesday, March 22, 1994. Enjoy!</p><p style="font-family:serif;text-size:9pt;">To unsubscribe, send an email to {sender}#{my-domain} with the subject "Unsubscribe please". You may briefly continue to recieve emails until the system processes your request.</p>
--===============1545014324==--
--===============1535165371==
Content-Type: image/gif
MIME-Version: 1.0
Content-Transfer-Encoding: base64
Content-ID: <30cbc076bf26fa38547141665a3874fc0bdc91b550d5b9523fbf033cd64d0d8b>
R0lGODlhhAMgAfcAAAAAAAEBAQICAgMDAwQEBAUFBQYGBgcHBwgICAkJCQoKCgsLCwwMDA0NDQ4O
Dg8PDxAQEBERERISEhMTExQUFBUVFRYWFhcXFxgYGBkZGRoaGhsbGxwcHB0dHR4eHh8fHyAgICEh
ISIiIiMjIyQkJCUlJSYmJicnJygoKCkpKSoqKisrKywsLC0tLS4uLi8vLzAwMDExMTIyMjMzMzQ0
NDU1NTY2Njc3Nzg4ODk5OTo6Ojs7Ozw8PD09PT4+Pj8/P0BAQEFBQUJCQkNDQ0REREVFRUZGRkdH
R0hISElJSUpKSktLS0xMTE1NTU5OTk9PT1BQUFFRUVJSUlNTU1RUVFVVVVZWVldXV1hYWFlZWVpa
WltbW1xcXF1dXV5eXl9fX2BgYGFhYWJiYmNjY2RkZGVlZWZmZmdnZ2hoaGlpaWpqamtra2xsbG1t
{ ... snipped 1462 lines worth of base-64 encoded data ... }
/pQ29JRRfUNJrQ5VOZVPzEP3CAxVzcM3zIPr2EdJ6dRKDoxUvcND5NIWCVEsBQYYmRMg4UUuKYT9
1FBCrKQ9+MVKGsTwHERX8eRCzEMrVsM3kMMmGhUmro7jxKRBXOU8SFVM8sS4eFA2+eRZomVKBGVK
vMMuRMIglFFatoZUAVEVHMIp9MKzpANRLoQ2DEI3yWVgCuZgEmZhGuZhIuZPRgREDEwS+eRaJmZi
yos5HeUS2ZBjHmWWJBHkJMYObWb8gCYPsc9oro/6EIxN3JD8mM5okiZjFsxicqbpyJBpwolpztBr
OiZqglFWVIVr/lBqpib4uI9uug9nMmZmFuf7dqCmcp6mD2Hmc+oGpwjnZ7LJEhlnD9XmDkXOcl5m
Y/LQb87mdopnbBIRDdlQZaqmdmYndlqQUjind8KncH6nq1SnD6GnbuJnfq5lZVIJZEZmJu1mpKhl
bhLoSrhmbZxTgf7ngjJoutBngy6mbCbFFPknhA5mQAAAOw==
--===============1535165371==--
EDIT: A few of my other recipients have also reported that this has happened in the past, but it only lasted a day or two, and they didn't think much of it. (I believe they are all also Gmail users...)
EDIT: Here's a slightly stripped-down version of the code that sends the emails. There is a file called addresses.py in the same directory that has a nested array with all the email addresses on my list.
#!/usr/bin/python
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
from email.MIMEImage import MIMEImage
import hashlib
import os
import datetime
from addresses import arrayTo # Addresses to send to
# Note: Calvin and Hobbes ran from 1985-11-18 to 1995-12-31
today = datetime.datetime.now()
comicDay = datetime.datetime(((today.year - 6) % 10 + 1990), today.month, today.day)
dateString = str(comicDay.year) + '-' + str(comicDay.month) + '-' + str(comicDay.day)
# Some definitions
for n in range(0,len(arrayTo)):
strTo = ''
numAddresses = len(arrayTo[n])
for i in range(0,numAddresses): # Concatenate address array into CSV
strTo += arrayTo[n][i]
if i < numAddresses - 1: # Don't end with a comma
strTo += ', '
strFrom = '{sender}#{my-domain}'
comicFile = '/path/to/files/picture_' + dateString + '.png'
if os.path.exists(comicFile):
# Open the image, assuming the image is in the current directory
fp = open(comicFile, 'rb')
msgImage = MIMEImage(fp.read())
fp.close()
# Generate a hash to use as the CID
comicHash = hashlib.sha256(comicFile).hexdigest()
# Create the root message and fill in the from, to, and subject headers
msgRoot = MIMEMultipart('related')
msgRoot['Subject'] = 'Calvin and Hobbes of the day'
msgRoot['From'] = strFrom
msgRoot['To'] = strTo
msgRoot.preamble = 'This is a multi-part message in MIME format.'
# Encapsulate the plain and HTML versions of the message body in an
# 'alternative' part, so message agents can decide which they want to display.
msgAlternative = MIMEMultipart('alternative')
msgRoot.attach(msgAlternative)
msgText = MIMEText('Calvin and Hobbes of the day email. Image not displayed for techical reasons. To unsubscribe, send an email to {sender}#{my-domain} with the subject "Unsubscribe please". You may briefly continue to recieve emails until the system processes your request.')
msgAlternative.attach(msgText)
# We reference the image in the IMG SRC attribute by the ID we chose above
msgText = MIMEText('<img src="cid:' + comicHash + '"><p>This Calvin and Hobbes was originally published on ' + comicDay.strftime('%A, %B %d, %Y') + '. Enjoy!</p><p style="font-family:serif;text-size:9pt;">To unsubscribe, send an email to {sender}#{my-domain} with the subject "Unsubscribe please". You may briefly continue to recieve emails until the system processes your request.</p>', 'html')
msgAlternative.attach(msgText)
# Define the image's ID as referenced above
msgImage.add_header('Content-ID', '<' + comicHash + '>')
msgRoot.attach(msgImage)
# Send the email
import smtplib
smtpObj = smtplib.SMTP('localhost', 25)
smtpObj.helo()
smtpStatus = smtpObj.sendmail(strFrom, arrayTo[n], msgRoot.as_string())
smtpObj.quit()
if (smtpStatus != {}):
# code to log this error
else:
# code to log this error
Related
I am reading a mail from stdin using
message = mailbox.email.message_from_file(sys.stdin)
and want to add an text file attachment. I tried the following:
new_msg = email.mime.multipart.MIMEMultipart('related')
old_msg = email.mime.message.MIMEMessage(message)
new_msg.attach(old_msg)
att_msg = email.mime.text.MIMEText("Textfile attachment")
att_msg.add_header('Content-Disposition', 'attachment', filename= 'my_attachment.txt')
new_msg.attach(att_msg)
maildir.add(new_msg)
where maildir = mailbox.Maildir('~/mail').
However, I get a message in ~/mail with two attachments ForwardedMessage.eml and my_attachment.txt.
My goal is to have the original message (with the same headers), but with the text file attached.
EDIT Let me give you an example. Original message:
To: foo#bar.com
From: User <user#mydomain.net>
Message-ID: <56F2AAD2.7030408#mydomain.net>
Date: Wed, 23 Mar 2016 15:40:18 +0100
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8; format=flowed
Content-Transfer-Encoding: 7bit
Testmessage
With my code:
Content-Type: multipart/related; boundary="===============7892775444970429949=="
MIME-Version: 1.0
--===============7892775444970429949==
Content-Type: message/rfc822
MIME-Version: 1.0
To: foo#bar.com
From: User <user#mydomain.net>
Message-ID: <56F2AAD2.7030408#mydomain.net>
Date: Wed, 23 Mar 2016 15:40:18 +0100
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8; format=flowed
Content-Transfer-Encoding: 7bit
Testmessage
--===============7892775444970429949==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="atach.txt"
Textfile attachment
--===============7892775444970429949==--
And this is what Thunderbird gives me (and what I want):
To: foo#bar.com
From: User <user#mydomain.net>
Message-ID: <56F2AAD2.7030408#mydomain.net>
Date: Wed, 23 Mar 2016 15:40:18 +0100
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="------------010607020403070301060303"
This is a multi-part message in MIME format.
--------------010607020403070301060303
Content-Type: text/plain; charset=utf-8; format=flowed
Content-Transfer-Encoding: 7bit
Testmessage
--------------010607020403070301060303
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="atach.txt"
Textfile attachment
--------------010607020403070301060303--
I have just tried out your code and it works perfect I will provide the working solution. I think it is better to import the needed module classes as sole classes for use in the code. As shown here
import sys
import mailbox
import email
from email.mime.multipart import MIMEMultipart
from email.mime.message import MIMEMessage
from email.mime.text import MIMEText
message = mailbox.email.message_from_file(sys.stdin)
maildir = mailbox.Maildir('./mail',create=True)
new_msg = MIMEMultipart('related')
old_msg = MIMEMessage(message)
new_msg.attach(old_msg)
att_msg = MIMEText("Textfile attachment")
att_msg.add_header('Content-Disposition', 'attachment',filename='atach.txt')
new_msg.attach(att_msg)
maildir.add(new_msg)
I have also passed an extra keyword arg to create the mailbox if it does not exist. create=True.
running the above and checking the mail Dir gives me the following I hope that is what you desire.
Content-Type: multipart/related; boundary="===============2731426334901210480=="
MIME-Version: 1.0
--===============2731426334901210480==
Content-Type: message/rfc822
MIME-Version: 1.0
Hello trial 2
--===============2731426334901210480==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="atach.txt"
Textfile attachment
--===============2731426334901210480==--
I really need your help. About a week I'm trying to configure mail on my server. I use nginx -> uwsgi -> django application.
The problem is that the mail server works only with the following backend:
class SSLEmailBackend(EmailBackend):
def open(self):
if self.connection:
return False
try:
self.connection = smtplib.SMTP_SSL(
self.host, self.port, local_hostname=DNS_NAME.get_fqdn())
if self.username and self.password:
self.connection.ehlo()
# Remove CRAM-MD5 authentication method
self.connection.esmtp_features['auth'] = 'PLAIN LOGIN'
self.connection.login(self.username, self.password)
return True
except:
if not self.fail_silently:
raise
My settings for it:
EMAIL_BACKEND = "my_app.backends.SSLEmailBackend"
EMAIL_HOST = "mail.my_mail_server.com"
EMAIL_PORT = 465
EMAIL_HOST_USER = "host#myhost.com"
EMAIL_HOST_PASSWORD = "my_pass"
DEFAULT_FROM_EMAIL = "host#myhost.com"
Locally, it works completely well!
The strangest thing that a message can be sent without any errors in the server console:
>> from django.core.mail import send_mail
>> send_mail('test email', 'hello world', '', ['my_test#gmail.com'])
The problem comes when I try to register a new user. I use Django-userena backend for registration. Registration is successful, but the emails come only on the server to /var/mail/user1
Text of email:
rom MAILER-DAEMON Sun Oct 26 02:06:01 2014
Return-path: <>
Envelope-to: webmaster#localhost
Delivery-date: Sun, 26 Oct 2014 02:06:01 +0400
Received: from Debian-exim by mail.my_mail_server.com with local (Exim 4.80)
id 1Xi9TF-0002Wp-Ml
for webmaster#localhost; Sun, 26 Oct 2014 02:06:01 +0400
X-Failed-Recipients: test#test.com
Auto-Submitted: auto-replied
From: Mail Delivery System <Mailer-Daemon#elib.rshu.ru>
To: webmaster#localhost
Subject: Mail delivery failed: returning message to sender
Message-Id: <E1Xi9TF-0002Wp-Ml#mail.my_mail_server.com>
Date: Sun, 26 Oct 2014 02:06:01 +0400
Status: O
This message was created automatically by mail delivery software.
A message that you sent could not be delivered to one or more of its
recipients. This is a permanent error. The following address(es) failed:
test#test.com
Mailing to remote domains not supported
------ This is a copy of the message, including all the headers. ------
Return-path: <webmaster#localhost>
Received: from localhost ([::1] helo=mail.my_mail_server.com)
by mail.my_mail_server.com with esmtp (Exim 4.80)
(envelope-from <webmaster#localhost>)
id 1Xi9TF-0002Wm-Lv
for test#test.com; Sun, 26 Oct 2014 02:06:01 +0400
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 8bit
Subject: =?utf-8?b?0KDQtdCz0LjRgdGC0YDQsNGG0LjRjyDQsiDRjdC70LXQutGC0YDQvtC90L0=?=
=?utf-8?b?0L7QuSDQsdC40LHQu9C40L7RgtC10LrQtSDQoNCT0JPQnNCj?=
From: webmaster#localhost
To: test#test.com
Date: Sat, 25 Oct 2014 22:06:01 -0000
....
I've been checking userena, nginx, etc. I can not understand what could be the problem. Why it works locally and on the server console messages can be sent. Please help.
Your mail server is not set up to accept remote mail forwarding. The error message from the server is 'Mailing to remote domains not supported.' So, whatever mail server you are connecting to is not recognizing that your web server is a 'trusted user' who's mail should be accepted and forwarded. I would try to get your mail service provider to whitelist your server for sending email.
I'm using Python with the framework Django. I am sending registration emails from my website (when a user register).
Using this snippet, I authenticate my email with DKIM (the DNS is correctly configured).
I also added SPF on my DNS.
Either on gmail and hotmail, I see spf=pass and dkim=pass.
But still, my email is flagged as spam. I made sure to use appropriate vocabulary, it's a text email with only 1 link (for registering). I am using no-reply#mydomain.com in FROM field for my email.
EDIT : After few changes I managed to have a "proper" header for my email. This is what it looks like (received on my hotmail account, still flagged as spam) (I replaced my domain name by mydomain.com and IP adress by stars, but they are correct) :
x-store-info:4r51+eLowCe79NzwdU2kRyU+pBy2R9QCQ99fuVSCLVOS47rfbRPiE7iaYhO1ERiggdK+K18l1xsWi4P40pG/T41xqL9zUAoU17o0RrecEQY1EuSFAsrgi0P9JxG/GRiKRWTxOOBRX7E=
Authentication-Results: hotmail.com; spf=pass (sender IP is ***.***.***.***) smtp.mailfrom=no-reply#mydomain.com; dkim=pass header.d=mydomain.com; x-hmca=pass header.id=no-reply#mydomain.com
X-SID-PRA: no-reply#mydomain.com
X-AUTH-Result: PASS
X-SID-Result: PASS
X-Message-Status: n:n
X-Message-Delivery: Vj0xLjE7dXM9MDtsPTA7YT0wO0Q9MjtHRD0yO1NDTD02
X-Message-Info: 11chDOWqoTn7F4e7hHYwxaXv9iZKZZyIKj/+21TGh6QZKczxEHQs4rb60Cxfdi09jTLkRJAecG6MEZoumj8BxQZCAkaW+YvuWguCAySgqkkiNyD1AL4MyP3BFzgaoF2ZXtaGotKTc8c/ChQJkPtnUkHdes5iALGuXQjNzKRE6CJjxAGItrK/tX2h6cQRePYbs40w9kwlyrSKjnMd0tsAss5uWWZc2J8a
Received: from mydomain.com ([***.***.***.***]) by BAY004-MC3F39.hotmail.com over TLS secured channel with Microsoft SMTPSVC(7.5.7601.22712);
Wed, 9 Jul 2014 08:18:05 -0700
Received: from mydomain.com (localhost.localdomain [127.0.0.1])
by mydomain.com (8.14.4/8.14.4/Debian-4) with ESMTP id s69FI3wS030630
for <*********#hotmail.fr>; Wed, 9 Jul 2014 17:18:03 +0200
DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=mydomain.com;
i=#mydomain.com; q=dns/txt; s=selector; t=1404919083; h=MIME-Version
: Content-Type : Content-Transfer-Encoding : Subject : From : To : Date
: Message-ID; bh=k7X+9bPwn6CQYmdYxiU1/FA763QwNClj01j8KmwLN2k=; b=Xg53TzAVYu7/7hnSJpH0NPsXhR2xasyW/Oo37XNSdWGOmZFP95way23mFMgT370IGv/rlTf+LJgYuH1grPRoVgR9Oif89uwLf9FIWx0CTwNlG9ONvKgTX3I91J8lAn/5KaMHW3sF/6C6CYhu9+nP8bh1JcuiuHq3zlYZLv2zQQQ=
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 8bit
Subject: Activation de votre compte Mydomain
From: Mydomain <no-reply#mydomain.com>
To: *********#hotmail.fr
Date: Wed, 09 Jul 2014 15:18:03 -0000
Message-ID: <20140709151803.30554.31146#mydomain.com>
Return-Path: no-reply#mydomain.com
X-OriginalArrivalTime: 09 Jul 2014 15:18:05.0604 (UTC) FILETIME=[FB999E40:01CF9B88]
Now I really don't understand what causes the email to be flagged as spam. Also checked blacklists, the domain isn't blacklisted.
I also did a test here, the results are the same : DKIM detected and check PASS, SPF PASS, SpamAssassin Score: -2.011 "Message is NOT marked as spam", only empty box is "DomainKeys Information : Message does not contain a DomainKeys Signature" (I don't find anything explaining the difference with DKIM).
NB : After goncalopp's comment, I wondered if this question shouldn't be on Serverfault instead of here. Should I remove it and ask there?
So after changing few settings I managed to have this header (masked IP address and domain for confidentiality). It sems to be clean header and passes all authentication tests :
Delivered-To: **********#gmail.com
Received: by 10.140.103.77 with SMTP id x71csp25213qge;
Thu, 17 Jul 2014 07:12:51 -0700 (PDT)
X-Received: by 10.180.109.168 with SMTP id ht8mr22242453wib.68.1405606370624;
Thu, 17 Jul 2014 07:12:50 -0700 (PDT)
Return-Path: <no-reply#**********.com>
Received: from mail.**********.com (**********com. [**********])
by mx.google.com with ESMTP id r8si9159599wia.83.2014.07.17.07.12.48
for <**********#gmail.com>;
Thu, 17 Jul 2014 07:12:50 -0700 (PDT)
Received-SPF: pass (google.com: domain of no-reply#**********.com designates ********** as permitted sender) client-ip=**********;
Authentication-Results: mx.google.com;
spf=pass (google.com: domain of no-reply#**********.com designates ********** as permitted sender) smtp.mail=no-reply#**********.com;
dkim=pass header.i=#**********.com
DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=**********.com;
i=#**********.com; q=dns/txt; s=selector; t=1405606368; h=MIME-Version
: Content-Type : Content-Transfer-Encoding : Subject : From : To : Date
: Message-ID; bh=PblNSkQvil33DWRvqe8DinhP7RB+k1OiDCBjgpR7DuE=; b=T4ti1yJsxUE2Uav6UYr+WznqZFrDVvAIoUN8G6voMWr4hUGVdC7u+QkR+d87SY4cN0nklbTWBXJ7gSOhR6r1d0NQZbg3jmRZzYxofPwayMRicYfUw1brWnrSnCUDQ98aUPv4qi9okb2/8vuu5yCKk5irarGrNQk+smnhVEFbqbA=
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 8bit
Subject: Activation de votre compte **********
From: ********** <no-reply#**********.com>
To: **********#gmail.com
Date: Thu, 17 Jul 2014 14:12:48 -0000
Message-ID: <20140717141248.2687.75060#**********.com>
It is still going straight to the spam folder. According to what I read here and there, it seems that my domain has to gain "trust" before being considered as "non-spam" (i.e. users have to flag it as "non-spam" and my domain should then be recognized better).
If anyone has any more suggestions, I take with pleasure :)
Hotmail/Outlook has the snds (Smart Network Data Service) you can register your ip and check the reputation, mail volume, bounces, traps. Maybe you have a bad reputation.
https://postmaster.live.com/snds/
I placed the raw-email into a string named a
i would like Python to tell me if this e-mail is TEXT or HTML
a = """From root#a1.local.tld Thu Jul 25 19:28:59 2013
Received: from a1.local.tld (localhost [127.0.0.1])
by a1.local.tld (8.14.4/8.14.4) with ESMTP id r6Q2SxeQ003866
for <ooo#a1.local.tld>; Thu, 25 Jul 2013 19:28:59 -0700
Received: (from root#localhost)
by a1.local.tld (8.14.4/8.14.4/Submit) id r6Q2Sxbh003865;
Thu, 25 Jul 2013 19:28:59 -0700
From: root#a1.local.tld
Subject: oooooooooooooooo
To: ooo#a1.local.tld
Cc:
X-Originating-IP: 192.168.15.127
X-Mailer: Webmin 1.420
Message-Id: <1374805739.3861#a1>
Date: Thu, 25 Jul 2013 19:28:59 -0700 (PDT)
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="bound1374805739"
This is a multi-part message in MIME format.
--bound1374805739
Content-Type: text/plain
Content-Transfer-Encoding: 7bit
ooooooooooooooooooooooooooooooooooooooooooooooo
ooooooooooooooooooooooooooooooooooooooooooooooo
ooooooooooooooooooooooooooooooooooooooooooooooo
--bound1374805739--"""
import email
b = email.message_from_string(a)
Content-Type: text/plain means plain text
Content-Type: text/html means HTML
This question already has answers here:
Parsing email with Python
(3 answers)
Closed 9 years ago.
The raw email usually looks something like this
From root#a1.local.tld Thu Jul 25 19:28:59 2013
Received: from a1.local.tld (localhost [127.0.0.1])
by a1.local.tld (8.14.4/8.14.4) with ESMTP id r6Q2SxeQ003866
for <ooo#a1.local.tld>; Thu, 25 Jul 2013 19:28:59 -0700
Received: (from root#localhost)
by a1.local.tld (8.14.4/8.14.4/Submit) id r6Q2Sxbh003865;
Thu, 25 Jul 2013 19:28:59 -0700
From: root#a1.local.tld
Subject: ooooooooooooooooooooooo
To: ooo#a1.local.tld
Cc:
X-Originating-IP: 192.168.15.127
X-Mailer: Webmin 1.420
Message-Id: <1374805739.3861#a1>
Date: Thu, 25 Jul 2013 19:28:59 -0700 (PDT)
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="bound1374805739"
This is a multi-part message in MIME format.
--bound1374805739
Content-Type: text/plain
Content-Transfer-Encoding: 7bit
ooooooooooooooooooooooooooooooo
ooooooooooooooooooooooooooooooo
ooooooooooooooooooooooooooooooo
--bound1374805739--
So if I wanted to code a PYTHON script to get the
From
To
Subject
Body
Is this the code I am looking for to built on of or is there a better method?
a='<title>aaa</title><title>aaa2</title><title>aaa3</title>'
import re
a1 = re.findall(r'<(title)>(.*?)<(/title)>', a)
I don't really understand what your final code snippet has to do with anything - you haven't mentioned anything about HTML until that point, so I don't know why you would suddenly be giving an example of parsing HTML (which you should never do with a regex anyway).
In any case, to answer your original question about getting the headers from an email message, Python includes code to do that in the standard library:
import email
msg = email.message_from_string(email_string)
msg['from'] # 'root#a1.local.tld'
msg['to'] # 'ooo#a1.local.tld'
Fortunately Python makes this simpler: http://docs.python.org/2.7/library/email.parser.html#email.parser.Parser
from email.parser import Parser
parser = Parser()
emailText = """PUT THE RAW TEXT OF YOUR EMAIL HERE"""
email = parser.parsestr(emailText)
print email.get('From')
print email.get('To')
print email.get('Subject')
The body is trickier. Call email.is_multipart(). If that's false, you can get your body by calling email.get_payload(). However, if it's true, email.get_payload() will return a list of messages, so you'll have to call get_payload() on each of those.
if email.is_multipart():
for part in email.get_payload():
print part.get_payload()
else:
print email.get_payload()
"Body" is not present in your sample email
Can use email module :
import email
msg = email.message_from_string(email_message_as_text)
Then use:
print email['To']
print email['From']
...
...
etc
You should probably use email.parser
s = """
From root#a1.local.tld Thu Jul 25 19:28:59 2013
Received: from a1.local.tld (localhost [127.0.0.1])
by a1.local.tld (8.14.4/8.14.4) with ESMTP id r6Q2SxeQ003866
for <ooo#a1.local.tld>; Thu, 25 Jul 2013 19:28:59 -0700
Received: (from root#localhost)
by a1.local.tld (8.14.4/8.14.4/Submit) id r6Q2Sxbh003865;
Thu, 25 Jul 2013 19:28:59 -0700
From: root#a1.local.tld
Subject: ooooooooooooooooooooooo
To: ooo#a1.local.tld
Cc:
X-Originating-IP: 192.168.15.127
X-Mailer: Webmin 1.420
Message-Id: <1374805739.3861#a1>
Date: Thu, 25 Jul 2013 19:28:59 -0700 (PDT)
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="bound1374805739"
This is a multi-part message in MIME format.
--bound1374805739
Content-Type: text/plain
Content-Transfer-Encoding: 7bit
ooooooooooooooooooooooooooooooo
ooooooooooooooooooooooooooooooo
ooooooooooooooooooooooooooooooo
--bound1374805739--
"""
import email.parser
msg = email.parser.Parser().parsestr(s)
help(msg)
you could write that raw content to a file
then read the file like this:
with open('in.txt', 'r') as file:
raw = file.readlines()
get_list = ['From:','To:','Subject:']
info_list = []
for i in raw:
for word in get_list:
if i.startswith(word):
info_list.append(i)
now info_list will be:
['From: root#a1.local.tld', 'Subject: ooooooooooooooooooooooo', 'To: ooo#a1.local.tld']
i dont see Body: in your raw content