Add from header in email [duplicate] - python

This question already has answers here:
Specify a sender when sending mail with Python (smtplib)
(6 answers)
Closed 6 months ago.
I made a simple program that automatically sends emails for me.
However when I send emails from riseup.net or protonmail I sometimes get failed to deliver because gmail requires "from" headers.
This is what the error looks like
This is the mail system at host mx1.riseup.net.
I'm sorry to have to inform you that your message could not be
delivered to one or more recipients. It's attached below.
For further assistance, please send mail to postmaster.
If you do so, please include this problem report. You can delete your
own text from the attached returned message.
The mail system
: host aspmx.l.google.com[74.125.142.27] said:
550-5.7.1
[198.252.153.129 11] Our system has detected that this message is
550-5.7.1 not RFC 5322 compliant: 550-5.7.1 'From' header is missing.
550-5.7.1 To reduce the amount of spam sent to Gmail, this message has been
550-5.7.1 blocked. Please visit 550-5.7.1
https://support.google.com/mail/?p=RfcMessageNonCompliant 550 5.7.1 and
review RFC 5322 specifications for more information. 62si8602934pjo.111 -
gsmtp (in reply to end of DATA command)
I looked up how to add a from header but I cannot get it to work for some reason.
This is my code
def send_mail():
context = ssl.create_default_context()
with smtplib.SMTP(smtp_server, 587) as server:
server.starttls(context=context)
server.login(susername, spassword)
server.sendmail(semail, recipient, message)
print("Email has been sent!")
edit: Riseup automatically adds this header when I send an email from within the browser but not when I use python to login to their SMTP server.

I was facing the same issue. I was able to resolve it by explicitly adding a From: field within the message body. For example, the below message body will work:
message = """From: <your email address>
To: <receiver's email address>\n
Subject: <your subject>\n
Hi, this is a test mail! """
Got the idea from the link in your comment:
Add Subject header to server.sendmail() in Python

I can't give an definite answer, but perhaps a few guidelines.
You wrote that you don't modify the return path when forwarding. However, it would be more relevant to know if you leave the envelope intact. The following assumes that you at least don't modify the envelope sender.
First, let's look at SPF:
Without special measures, it is understandable that Google treats the messages as spam. SPF works like that (oversimplified):
When a message arrives, the receiving server extracts the pretended sender domain from the envelope address (pretended because the envelope can easily be faked), then asks the DNS server of that domain whether the current communication partner's IP address is authorized to send email in behalf of that domain. If it isn't, it is likely that the message is treated as spam.
This is what happens in your case (without SRS). The original envelope sender domain's DNS server probably does not have your EXIM SMTP server in the list of hosts which may send email on behalf of that domain. You can't do anything about that, unless you control that DNS server.
SRS theoretically can mitigate the problem, but it has its own issues. The main problem is that every SMTP server which is involved in transporting the respective messages must handle the respective headers correctly.
You have described that everything was working with SRS turned on, but it suddenly stopped a few days ago. My personal guess is that since an additional SMTP server is involved in transporting your forwarded messages, and that this server doesn't treat SRS correctly. Something bad could even happen before your EXIM server receives that messages.
DKIM shouldn't have the problems denoted above as long as you leave the envelope sender address intact.
Now, my first advice would be to send messages to your EXIM server's special, forwarded address from as many different sender domains as possible. It would be very interesting to know whether all of the forwarded messages get rejected, or only a few of them. The result could give a hint about where the problem is. You probably would want to enable SRS for this test.
You should also check which authorization the messages already have which arrive at your EXIM server to your special address. I have no clue about EXIM, so I can't tell you whether it supports checking SPF or DKIM headers. But what I can say for sure is that it wouldn't be the first time that somebody at the original sender's site misconfigures DKIM or SPF; in the latter case, SRS won't help of course.
At least in case of SPF, you can check the situation yourself without re-configuring EXIM.
First, store one of the problematic messages (in addition to or instead of forwarding it). In the headers of that message, you can identify the IP address of the SMTP server which has delivered the message to your EXIM server. For clarification: If the message ran through multiple SMTP servers, there would be multiple Received: header lines; you need the one which designates the last SMTP server which directly connected to your EXIM server when delivering the message. Write down the IP address of that server.
Next, identify the envelope sender domain. That may be a bit hard because SMTP servers usually do not add the envelope data to the headers (again, no clue about EXIM). That is, email client software can't show that data. But it should be in the logs. You really need to get the sender's domain from the envelope data, not the normal message headers.
Next, use software like host or dig (or eventually some online service) to examine the DNS SPF entries of the envelope sender's domain. Check if the IP address from step 1 is in the list of allowed servers.
The next thing you could test is to turn off SPF and DKIM at all and to filter out the respective headers before forwarding the message. After all, it may be better to not authenticate a message at all than to authenticate it in a way that makes the receiver think that it has been tampered with. Of course, this is only for testing to gain further insight.
Finally, violating the precondition from the second paragraph, you could purposely change the envelope sender (replacing the envelope sender by your own email address with a domain part whose DNS entries are under your control) and turn off SRS. That way, when forwarding the message, the receiving server would consult your DNS server for the SPF checks. If you have set it up correctly, no more problems with SPF should arise. In this case, you should filter out headers which designate the original envelope sender (as stated above, it is usually not in the headers anyway, but I only know sendmail, so your mileage may vary).
However, when changing the envelope sender, you'll have problems with DKIM, so you should remove the DKIM headers in this case.
Happy testing, and good luck.
P.S. I'll eventually update the answer and give further hints (if I am able to) when you give test results or explain more precisely whether or not you change the envelope.

Related

determine smtp server for a given email address python smtplib

Given an email address is it possible to determine what the smtp address is using python. I am building an email application using python smtplib.
Thanks
The Python smtplib module does not perform mail routing, so it leaves that to a smart host.
You could use dnspython to look up MX records for the destination domain (and A and AAAA records if there is no MX record). The resulting address you can then pass to smtplib.
However, this is only a small fraction of the work that is needed to implement proper mail routing: If the target mail server is unreachable or times out, you are supposed to try the next server. Similarly if it responds with a 4xx error code. If all servers are unavailable, you need to temporarily store the message locally, so you need to implement your own mail queue. Furthermore, your external IP address may be blacklisted for mail delivery.
Therefore, it is usually easier to install a local mail server such as Exim or Postfix and use that to inject mail, possibly routing it via a smart host with good email reputation to avoid blacklisting.

What is the proper way to ACTUALLY SEND mail from (Python) code?

Disclaimer: I hesitated on the title, due to the broad nature of this question (see below), other options included:
How to send a mail from localhost, using Python code only?
How to send email from Python code, without usage of external SMTP server?
Is it possible to send an email DIRECTLY to it's destination, using localhost and Python only?
First, a little bit of context:
For the sake of learning I am building a website with user registration feature. The idea is that after registration user will receive an email with activation link. I would like to compose & send email from Python code, and that is the part where I would like to ask for some clarifications.
My understanding, before I began (obviously naive =) can be illustrated like this (given that there is a legitimate email address user#example.com):
After searching for examples, I bumped into some questions & answers on stackoverflow (1, 2, 3, 4). From these I've distilled the following snippet, to compose and send an email from Python code:
import smtplib
from email.message import EmailMessage
message = EmailMessage()
message.set_content('Message content here')
message['Subject'] = 'Your subject here'
message['From'] = 'me#example.com'
message['To'] = 'user#example.com'
smtp_server = smtplib.SMTP('smtp.server.address:587')
smtp_server.send_message(message)
smtp_server.quit()
Next (obvious) question was what to pass to smtplib.SMTP() instead of 'smtp.server.address:587'. From the comments to this answer, I discovered that local SMTP server (just for testing purposes though) could be started via python3 -m smtpd -c DebuggingServer -n localhost:1025, then smtp_server = smtplib.SMTP('smtp.server.address:587') could be changed to smtp_server = smtplib.SMTP('localhost:1025') and all the sent emails will be displayed in the console (from where python3 -m smtpd -c DebuggingServer -n localhost:1025 command was executed), being enough for testing — it was not what I wanted (my aim was — the ability to send a mail to 'real-world' email address from local machine, using Python code only).
So, the next step would be to setup a local SMTP server, capable of sending an email to external 'real-world' email-address (as I wanted to do it all from Python code, so the server itself would better be implemented in Python too). I recalled reading in some magazine (in early 2000), that spammers use local servers for sending mails (that particular article was talking about Sambar, development for which have ended in 2007, and which was not written in Python :-) I thought there should be some present-day solution with similar functionality. So I started searching, my hope was to find (on stackoverflow or elsewhere) a reasonably short code snippet, which will do what I wanted. I haven't found such a code snippet, but I came across a snippet titled (Python) Send Email without Mail Server (which uses chilkat API), though all I needed (supposedly) was right there, in the comments to code, the first line clearly stated:
Is it really possible to send email without connecting to a mail server? Not really.
and a few lines below:
Here's what happens inside those other components that claim to not need a mail server: The component does a DNS MX lookup using the intended recipient's email address to find the mail server (i.e. SMTP server) for that domain. It then connects to that server and delivers the email. You're still connecting to an SMTP server — just not YOUR server.
Reading that, made me understand — I, clearly, was lacking some details in my understanding (reflected on picture above) of the process. To correct this I have read the whole RFC on SMTP.
After reading the RFC, my improved understanding of the process, might be pictured like this:
From this understanding, came the actual questions I'd like to clarify:
Can my "improved understanding" be considered correct, as a general picture?
What addresses, exactly, are returned by MX lookup?
using host -t mx gmail.com command (suggested by this answer), I was able to retrieve the following:
gmail.com mail is handled by 10 alt1.gmail-smtp-in.l.google.com.
gmail.com mail is handled by 20 alt2.gmail-smtp-in.l.google.com.
gmail.com mail is handled by 40 alt4.gmail-smtp-in.l.google.com.
gmail.com mail is handled by 30 alt3.gmail-smtp-in.l.google.com.
gmail.com mail is handled by 5 gmail-smtp-in.l.google.com.
- but none of these are mentioned in the [official docs][13] (ones that are there: `smtp-relay.gmail.com`, `smtp.gmail.com`, `aspmx.l.google.com`)
Is authentication always needed to pass an email to SMTP-server of an established mail service (say gmail)?
I understand that to use, say smtp.gmail.com for mail submission, you'll need, regardless if the recipient has a #gmail address or not (as it stated in docs):
Your full Gmail or G Suite email address is required for authentication.
But, if an email to user#gmail.com is submitted to SMTP-server not owned by gmail, then it'll be redirected to one of the gmail servers (directly or via gateway/relay). In this case (I assume) sender of an email will only need to authenticate on mail submission, so after that gmail server will accept the mail without authentication?
If yes, what is preventing me from "pretending" to be such a gateway/relay and hand over emails directly to their designated SMTPs? Then it, also should be pretty easy to write a "proxy-SMTP", which will just search for an appropriate server via MX lookup, and hand an email to it, sort of, directly.
Documentation on gmail SMTP, also mentions aspmx.l.google.com server, which does not require authentication, though:
Mail can only be sent to Gmail or G Suite users.
With that being said, I assume the following snippet should work, for submitting a mail to ExistingUser#gmail.com mailbox:
<!-- language: lang-python -->
import smtplib
from email.message import EmailMessage
message = EmailMessage()
message.set_content('Message test content')
message['Subject'] = 'Test mail!'
message['From'] = 'me#whatever.com'
message['To'] = 'ExistingUser#gmail.com'
smtp_server = smtplib.SMTP('aspmx.l.google.com:25')
smtp_server.send_message(message)
smtp_server.quit()
When ran, the code above (with ExistingUser#gmail.com replaced by the valid mail) throws OSError: [Errno 65] No route to host. All I want to confirm here is that the communication to aspmx.l.google.com is handled correctly in code.
Your understanding of how mail works is roughly correct. Some additional notes that may clear things up:
SMTP is used for two distinct purposes. You seem to be confusing these two.:
The first use, typically called "submission", is to send a mail from an MUA (Mail User Agent, your mail program, Outlook, Thunderbird, ...) to an MTA (Mail Transfer Agent, typically called "mail server"). MTAs are run by your ISP, or by mail-providers such as GMail. Typically, their use is restricted by either IP address (only customers of said ISP can use it), or username/password.
The second use is to send mail from one MTA to another MTA. This part is, usually, wide open, since you are probably willing to accept inbound mail from anyone. This is also the location where anti-spam measures are taken.
In order to send a mail, you need, at least, the second part of SMTP: the ability to talk to another MTA to deliver the mail.
The typical way to send mails is to compose the mail in your application, then send it off to an MTA mail server for delivery. Depending on your setup, that MTA can be either installed on the same machine as your Python code is running on (localhost), or can be a more "central" mail server (possibly requiring authentication).
"Your" MTA will take care of all the nasty details of delivering mail such as:
Doing DNS lookups to find out the MTA's to contact to relay the mail. This includes MX-lookup, but also other fallback mechanisms such as A-records.
Retrying delivery, if the first attempt fails temporarily
Generating a bounce message, if the message fails permanently
Make multiple copies of the message, in case of multiple recipients on different domains
Signing the message with DKIM to reduce the chance of it being marked as SPAM.
...
You could, of course, re-implement all these features within your own Python code, and effectively combine an MTA with your application, but I strongly advise against it. Mail is surprisingly hard to get right...
Bottom line: Try to send the mail via SMTP to the mail server of your provider or another mail service. If that is not possible: think really hard if you want to run your own mail server. Being marked as a spammer happens easily; getting removed from spam-lists is much harder. Don't re-implement SMTP-code in your application.
Thanks to these answers, to my additional questions: 1, 2, 3, as well as these two questions (and answers) of other people: one, two — I think I am now ready to answer the questions I have posted, on my own.
I will address the questions one by one:
Yes, as a general picture, sending of an email can be portrayed like this:
MX lookup returns address(es) of server(s) which receive email destined to the specified domain.
As to "Why smtp-relay.gmail.com, smtp.gmail.com, aspmx.l.google.com are not returned by host -t mx gmail.com command?". This point is, pretty much, covered in another answer to this question. The main points to grasp here are:
servers returned by MX lookup are responsible for receiving of emails for the domain (gmail, in this particular case)
servers listed in gmail docs are meant for the mail sending (i.e. mails that gmail user wants to send, to other gmail user or otherwise, are submitted to those servers)
Authentication is not needed, for servers receiving emails (i.e. the ones returned by MX lookup).
There are a couple things that prevent such servers from being abused:
many ISPs block outbound connections to port 25 (which is default port for mail receiving servers), to prevent such "direct" mail sending
there are numerous measures taken on the side of receiving servers, which are, mainly, intended to prevent spamming, but as a result will, likely, prevent such "direct" mail sending, as well (some examples are: DNSBL — list of blocked IPs, DKIM — is an email authentication method designed to detect forged sender addresses in emails (if you do not have your own, legitimate, mail server, you will use someone other's domain for From field, that is where you might be hit by DKIM)
Code snippet is OK. The error is produced, in all probability, due to the blocking on the ISP's side.
With all that being said, code snippet:
import smtplib
from email.message import EmailMessage
message = EmailMessage()
message.set_content('Message content here')
message['Subject'] = 'Your subject here'
message['From'] = 'me#example.com'
message['To'] = 'user#example.com'
smtp_server = smtplib.SMTP('smtp.server.address:25')
smtp_server.send_message(message)
smtp_server.quit()
will actually send an email (see this question, for real-world, working example) given that smtp.server.address:25 is legitimate server and there are no blockings on ISP's and/or smtp.server.address side.

How to detect bounce emails

How do you detect "bounceed" email replies and other automated responses for failed delivery attempts in Python?
I'm implementing a simple server to relay messages between email and comments inside a custom web application. Because my comment model supports a "reply to all" feature, if two emails in a comment thread become invalid, there would possibly be an infinite email chain where my system would send out an email, get a bounceback email, relay this to the other invalid email, get a bounceback email, relay this back to the first, ad infinitum.
I want to avoid this. Is there a standard error code used for bounced or rejected emails that I could check for, ideally with Python's imaplib package?
Wikipedia has some good info on this matter. RFC6522 gives the error code for any administrative message from a SMTP server as Error 500.
You could try listening for an error message with Error 500. That should work.
Quoting Wikipedia,
The format for the reporting of administrative messages is defined by
RFC 6522. A DSN may be a MIME multipart/report message composed of
three parts:
a human readable explanation; a machine parsable
message/delivery-status, a list of "name: type; value" lines that
state several possible fields; and the original message, or a portion
thereof, as an entity of type message/rfc822. The second part of a DSN
is also quite readable. It is essential to understand which MTA played
which role. The Reporting-MTA is responsible for composing and sending
the DSN.
When a Remote-MTA rejects a message during an SMTP transaction, a
field Diagnostic-Code of type smtp may be used to report that value.
Note that beside the numerical 3-digit value, the SMTP response
contains itself a human readable part. The information
Remote-MTA: dns; smtp.store.example [192.0.2.3] Diagnostic-Code: smtp;
550 No such user here is sometimes reported as, e.g., while talking to
smtp.store.example [192.0.2.3]
RCPT TO:nonexistinguser#store.example <<< 550 No such user here
I'm not sure about imaplib though since I'm a beginner with Python.
Your SMTP Envelope from address should not be the same as your RFC822 From Header address. Then any SMTP errors will go to the bounce address, but any real emails will go to the From address. Mailing List Managers use VERP to detect problems, by using a different envelope From address for each delivery.
Avoid reacting to messages whose Return-Path isn't in From, or that contain an Auto-Submitted or X-Loop header field, or that have a bodypart with type multipart/report.
You may also want to specify Auto-Submitted: auto-generated on your outgoing mail. I expect that if you do as Max says that'll take care of the problem, but Auto-Submitted isn't expensive.

How to catch the SMTPRecipientsRefused exception (using a remote SMTP server and django)?

I'm trying to understand how this works.
When I normally send and email and the recipient doesn't exist, or some other error occurs, an email is send back containing the info about the error and the status. This can take some time. My question here is how can smtplib catch this error if this response take time?
When I send an email using smtplib it never raises the SMTPRecipientsRefused exception. It just sends the email and later, when purposely using an invalid email address, I get the "Delivery to the following recipient failed permanently:" error in my reply-to email box. This doesn't help me as I am trying to clean my email address database from invalid email addresses.
There is the verify function:
SMTP.verify(address)
But I don't believe this is a real option. Note from python docs on VRFY:
"Many sites disable SMTP VRFY in order to foil spammers."
A note on my testing environment: I'm using django and a remote SMTP server (gmail/apps). Q1: Is this the reason for not being able to catch the error? Should I be using a local server?
Q2: Is there a way to do this except from parsing my actual error emails from the reply-to email box?
Thanks in advance for any thoughts on the matter!
Yes this is why you don't get the Exception. Using a local server will not help because your local server has no idea if a given email address is valid. Only the destination domain's MX mail server has any clue, and it often isn't motivated to tell you until much later.
Not really. As the other answer suggests, try Python's imaplib or poplib to help you retrieve bounce messages.
No idea what your application is, but another option if you have an associated website is to periodically ask your users upon login to verify/update their email address.
Yeah, unfortunately SMTP VRFY has been disabled on most servers for many years, precicesly because this can be used by spammers to quickly search a server for valid emails. You'll have to do it by hand or scrape emails. python-imap will help you here. Good luck!

How do I get started processing email related to website activity?

I am writing a web application that requires user interaction via email. I'm curious if there is a best practice or recommended source for learning about processing email. I am writing my application in Python, but I'm not sure what mail server to use or how to format the message or subject line to account for automated processing. I'm also looking for guidance on processing bouncebacks.
There are some pretty serious concerns here for how to send email automatically, and here are a few:
Use an email library. Python includes one called 'email'. This is your friend, it will stop you from doing anything tragically wrong. Read an example from the Python Manual.
Some points that will stop you from getting blocked by spam filters:
Always send from a valid email address. You must be able to send email to this address and have it received (it can go into /dev/null after it's received, but it must be possible to /deliver/ there). This will stop spam filters that do Sender Address Verification from blocking your mail.
The email address you send from on the server.sendmail(fromaddr, [toaddr]) line will be where bounces go. The From: line in the email is a totally different address, and that's where mail will go when the user hits 'Reply:'. Use this to your advantage, bounces can go to one place, while reply goes to another.
Send email to a local mail server, I recommend postfix. This local server will receive your mail and be responsible for sending it to your upstream server. Once it has been delivered to the local server, treat it as 'sent' from a programmatic point of view.
If you have a site that is on a static ip in a datacenter of good reputation, don't be afraid to simply relay the mail directly to the internet. If you're in a datacenter full of script kiddies and spammers, you will need to relay this mail via a public MTA of good reputation, hopefully you will be able to work this out without a hassle.
Don't send an email in only HTML. Always send it in Plain and HTML, or just Plain. Be nice, I use a text only email client, and you don't want to annoy me.
Verify that you're not running SPF on your email domain, or get it configured to allow your server to send the mail. Do this by doing a TXT lookup on your domain.
$ dig google.com txt
...snip...
;; ANSWER SECTION:
google.com. 300 IN TXT "v=spf1 include:_netblocks.google.com ~all"
As you can see from that result, there's an SPF record there. If you don't have SPF, there won't be a TXT record. Read more about SPF on wikipedia.
Hope that helps.
Some general information with regards to automated mail processing...
First, the mail server "brand" itself isn't that important for broadcasting or receiving emails. All of them support the standard smtp / pop3 communications protocol. Most even have IMAP support and have some level of spam filtering. That said, try to use a current generation email server.
Second, be aware that in an effort to reduce spam a lot of the receiving mail servers out there will simply throw a message away instead of responding back that a mail account doesn't exist. Which means you may not receive those.
Bear in mind that getting past spam filters is an art. A number of isp's watch for duplicate messages, messages that look like spam based on keywords or other content, etc. This is sometimes independent of the quantity of messages sent; I've seen messages with as few as 50 copies get blocked by AOL even though they were legitimate emails. So, testing is your friend and look into this article on wikipedia on anti-spam techniques. Then make sure your not doing that crap.
**
As far as processing the messages, just remember it's a queued system. Connect to the server via POP3 to retrieve messages, open it, do some action, delete the message or archive it, and move on.
With regards to bouncebacks, let the mail server do most of the work. You should be able to configure it to notify a certain email account on the server in the event that it is unable to deliver a message. You can check that account periodically and process the Non Delivery Reports as necessary.

Categories