I have a python script that sends out emails. The emails are being sent out with no issues.
However, when I get the mails and open them up, their "to:" field do not show the recipients. It's just blank. I want to show all the recipients. And since I'm not using any "bcc" configuration in my script, I'm befuddled as to how this could be.
Here's the code I'm using:
#!/usr/bin/env python
you = [ "MyEmail1#MyEmail.com", "MyEmail2#MyEmail.com" ]
for eachrecord in fformatErrMessage:
# Preparing all variables #
msg = MIMEMultipart()
msg['Subject'] = subjectMsg
part1 = MIMEText(text, 'plain')
part2 = MIMEText(html, 'html')
msg.attach(part1)
msg.attach(part2)
s = smtplib.SMTP('localhost')
s.sendmail(me, you, msg.as_string())
s.quit()
I have tried replacing the you with:
you = "MyEmail1#MyEmail.com"
thinking maybe the list is the problem - but that did not work.
When sending emails, servers do not look at the To:-Field. Instead, email servers have a separate way of transmitting recipient addresses, sometimes called the "envelope", which they use to route and deliver mail. The client never receives that envelope, it instead uses the To:-field in the message headers.
The sendmail() call simply sets the addresses of the SMTP envelope. If you want the To:-field to show up in the mail itself, you must set the appropriate header:
msg['To'] = "foo#bar.com"
This is, btw, how BCC works: The addresses on the envelope is simply not repeated in the message headers.
Related
For my use case, I would like to manually set the displayed email addresses in the "to" and "from" field headers of the email, separate from the actual email recipient and sender. I am currently using the smtplib library in python and have managed to accomplish the desired effect with the "to" field and was looking to replicate it for the "from" field as well.
What I have so far:
EMAIL_ADDRESS_G = 'ayush.warikoo77#gmail.com'
from email.message import EmailMessage
with smtplib.SMTP_SSL('smtp.gmail.com', 465) as smtp:
smtp.login(EMAIL_ADDRESS_G, EMAIL_PASSWORD_G)
# What I would like to be displayed in the email
msg = EmailMessage()
msg["Subject"] = "Test"
msg["To"] = 'test#gmail.com' # shows up
msg['From'] = 'test#gmail.com' # does not show up
msg.set_content("Test body")
# Where I would like to be setting the actual email sender and recipient
smtp.send_message(msg, from_addr=EMAIL_ADDRESS_G, to_addrs=EMAIL_ADDRESS_G)
The above code produces the following:
As shown, the "to" field displays the desired set address, while the "from" field displays my actual email instead of "test#gmail.com". I believe it is being set when I call login with the account, but I am unsure if I can override it. Also happy to use another python email library, if it is not possible with smtplib.
Current --> Desired
To: test#gmail.com
From: ayush.warikoo77#gmail.com --> test#gmail.com
Actual Sender: ayush.warikoo77#gmail.com
Actual Reciever: ayush.warikoo77#gmail.com
Note that this would be used for archiving purposes, where a designated email client might actually be sending the emails, however, I would like the email to use the to and from fields of the message it is trying to document. So the desired displayed "from" field is separate from the actual sender.
Authenticated Gmail SMTP prevents you from spoofing the From header, presumably to prevent abuse.
For archiving purposes, using IMAP’s APPEND command will allow you to place whatever you like in your own mailbox (as it doesn’t count as sending email) and may be a better solution. (You will need to use an App Specific Password or OAUTH to login though).
I've just joined a project and have been trying to figure why some emails are showing up as they should on Gmail but when I open then with a client like Thunderbird or Outlook the attached PDFs do now show up.
As an additional detail if I forward the mail from Thunderbird/Tutlook to a Gmail account the attached pdf will appear and if I send it back to the Thunderbird/Outlook - connected account it will again appear, so Gmail fixes something that's wrong in the code.
This is my second time dealing with emails, the first being mostly copying some code to see if it works, so if you're willing to explain it to me in addition to helping me fix it, I'd appreciate it greatly.
I'll post the code here and then add some additional information on what I tried below, to keep this a bit cleaner.
So, here's the code:
from email.message import EmailMessage
from email import encoders
from email.mime.base import MIMEBase
import smtplib
msg = EmailMessage()
msg['Subject'] = subject
msg['From'] = "someaddress"
msg['To'] = user_email
msg.set_content('Certification')
msg.add_alternative("""<!DOCTYPE html>
<html>
<body>
Stuff...
</body>
</html>
""", subtype='html')
filename = 'somefilename'
pdf_filename = 'certificate.pdf'
with open(filename, "rb") as attachment:
part = MIMEBase("application", "octet-stream")
part.set_payload(attachment.read())
encoders.encode_base64(part)
part.add_header(
"Content-Disposition",
"attachment", filename=pdf_filename
)
try:
msg.attach(part)
with smtplib.SMTP('someIP', port) as smtp:
smtp.send_message(msg)
I've seen some similar issues (or actually the same issue) before, and some solutions suggested using a MIMEMultipart-mixed message object instead of an email one like this:
msg=MIMEMultipart('mixed') instead of msg = EmailMessage() but because add_alternative is not a MIMEMultipart method, I cannot do that without changing that part.
(The above was suggested on this post - which is exactly the same issue as mine, but unfortunately I could not use the same fix)
What I tried doing was calling a
msg.make_mixed() below msg=Email.Message() hoping that the mixed type (I don't understand email types yet) would solve the problem, but when I tried sending an email that way I got a Status=4, Failed to send file, error.
I would also really appreciate if you could offer any suggestion for a resource to learn some more about sending and receiving emails (from a python perspective).
Thank you!
The problem here is that you have directly attached a pre-built MIME part to a multipart/alternative message. It ends in an incorrect message that may be poorly processed by mail readers.
In the email.message interface, you should use the add_attachement method. It will handle the base64 encoding and will change the message into a multipart/mixed one:
with open(filename, "rb") as attachment:
msg.add_attachment(attachment.read(), maintype='application',
subtype='octet-stream', filename=pdf_filename)
try:
with smtplib.SMTP('someIP', port) as smtp:
smtp.send_message(msg)
I want to send an email to multiple users. Right now, I am only able to send it to one user. I want to make a property file so that whenever I need to add or remove any user from the list, I dont have to edit anything in .py file.
I am able to send the email to one user
import smtplib
import email.utils
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
me = abc#an.com
you = jud#gm.com
msg = MIMEMultipart('alternative')
msg['Subject']="subject of the email"
msg['From"]=me
msg['To']=you
text="hi"
html= '''body of email'''
part1=MIMEText(text, 'plain')
part1=MIMEText(html, 'html')
msg.attach(part1)
msg.attach(part2)
s = smtplib.SMTP(host,port)
s.sendmail(me,you, msg.as_string())
s.quit()
the email should go to multiple users.
The argument you can be a list of email addresses. You will need to adapt your code to set the To: header to accept a list of strings
msg['To'] = '.'.join(you)
or you can use a placeholder like
msg['To'] = 'undisclosed-recipients:;'
but other than that, your existing code should just work.
In some more detail, the latter is basically equivalent to putting all the addresses in a Bcc: header, so that the recipients cannot see each others' addresses.
To populate you from a file, try
with open(filename) as f:
you = f.readlines()
where the file contains one email address per line.
When using the smtplib library to send emails to phone numbers (ex. number#tmomail.net), my email gets blocked with the message 550 permanent failure for one or more recipients.
I can successfully send emails using the smtplib library to normal emails. I have used my script to send emails to my personal email.
I can also send emails to the phone number successfully using the manual gmail client. If I log into google manually, fill out the form, the email sends to the number perfectly fine.
with smtplib.SMTP('smtp.gmail.com', 587) as smtp:
smtp.ehlo()
smtp.starttls()
smtp.ehlo()
smtp.login(self.email, self.password)
subject = 'test'
body = 'hello world'
msg = f'Subject: {subject}\n\n{body}'
smtp.sendmail(self.email, validNumber#carrier.com, msg)
Can someone tell me how to make the text go through unblocked the same way it does when it emails normal gmails?
I believe this issue is specific to T-Mobile numbers. Refer to the answer here:
https://support.t-mobile.com/thread/116618
"T-Mobile is now blocking traffic where the sending Domain is altered from the true sending address: IE support#customerservice.com, when the domain is actually is support#gmail.com. senders will receive a 550 bounceback error . To correct this issue, Senders will need to revert their sending address to their actual email address."
I'm having a file.txt file which has many lines. I want that any one line is chosen at random and emailed. This is looped thrice.
import smtplib,datetime,random
def mail(em):
#print "yo"
fromAddress = "atadmorecouth#gmail.com"
toAddress = "atadmorecouth#gmail.com"
subject = "WOW " + str(datetime.datetime.now())
#print subject
msg = em
server=smtplib.SMTP("smtp.gmail.com", 587)
server.starttls()
password = "mypassword"
server.login(fromAddress, password)
server.sendmail(fromAddress, toAddress, msg)
#print server.sendmail(fromAddress, toAddress, msg)
for i in range(0,3):
em=str(random.choice(list(open('file.txt'))))
mail(em)
This code does not work. The login and everything is fine. The only problem I notice is that server.sendmail(fromAddress, toAddress, msg) returns an empty {}
What could be the possible fix to this? Whats the problem in first place?
I have run the mail() function in the terminal and that seems to work fine.
All the files are hosted here
First, as the docs say:
If this method does not raise an exception, it returns a dictionary, with one entry for each recipient that was refused.
So, the fact that you're getting back {} isn't a problem; it means that you had no errors.
Second, what you're sending is not a valid message. A message must contain headers, then a blank line, then the body. And the headers should contain at least From: and To:.
The smtplib library doesn't do this for you; as explained in the example:
Note that the headers to be included with the message must be included in the message as entered; this example doesn’t do any processing of the RFC 822 headers. In particular, the ‘To’ and ‘From’ addresses must be included in the message headers explicitly.
...
Note: In general, you will want to use the email package’s features to construct an email message, which you can then convert to a string and send via sendmail(); see email: Examples.
Or, in the sendmail docs:
Note: The from_addr and to_addrs parameters are used to construct the message envelope used by the transport agents. The SMTP does not modify the message headers in any way.
In this case (as in the example), it's simple enough to just craft the message manually:
msg = "From: {}\r\nTo: {}\r\n\r\n{}\r\n".format(fromAddress, toAddress, em)
Finally, you really should call server.quit() at the end of the mail function. While (at least in CPython) the server object will be destroyed as soon as the function ends, unlike many other objects in Python, SMTP objects do not call close when destroyed, much less quit. So, from the server's point of view, you're suddenly dropping connection. While the RFCs suggest that a server should work just fine without a QUIT, and most of them do, they also recommend that the client should always send it and wait for a response, so… why not do it?