Sending Mail in Python - Error code - SMTPDataError: 451, b 4.3.0 Mail server temporarily rejected message - python-3.x

I am able to send mail without issue when I implement the same code very plain without using any functions. But when I try to send mail using a function I am getting mail as my senders account is disabled and it is blocking my mail and account.
Have to implement a code for sending mails after certain filters are met in a function so that it can be used to send mail whenever wanted.
My code snippet:
import smtplib
def setup_mail():
global smtpObj,sender,receivers,message
sender = 'sample#gmail.com'
receivers = ['sample1#gmail.com','sample2#gmail.com']
message = """From: From Person <from#fromdomain.com>
To: To Person <to#todomain.com>
Subject: 1 MIN candle 15 points alert
TIME: watch out next 2 minutes
"""
smtpObj = smtplib.SMTP_SSL('smtp.gmail.com', 465)
smtpObj.login("sample#gmail.com","samplepassword")
setup_mail()
def sending_mails(smtpObj):
smtpObj.sendmail(sender, receivers, message)
for i in range(3):
sending_mails(smtpObj);
print("Successfully sent email")
The error i got,
Traceback (most recent call last): File "C:/Users/Arun/PycharmProjects/Astro/venv/Scripts/ZERODHA_DEV/sendmail.py", line 22, in sending_mails(smtpObj); File "C:/Users/Arun/PycharmProjects/Astro/venv/Scripts/ZERODHA_DEV/sendmail.py", line 20, in sending_mails smtpObj.sendmail(sender, receivers, message) File "C:\Python\lib\smtplib.py", line 888, in sendmail raise SMTPDataError(code, resp) smtplib.SMTPDataError: (451, b'4.3.0 Mail server temporarily rejected message. s77sm14888153pfc.164 - gsmtp')
However it works with a simple code like,
import smtplib
global smtpObj,sender,receivers,message
sender = 'sample#gmail.com'
receivers = ['sample1#gmail.com','sample2#gmail.com']
message = """From: From Person <from#fromdomain.com>
To: To Person <to#todomain.com>
Subject: 1 MIN candle 15 points alert
TIME: watch out next 2 minutes
"""
smtpObj = smtplib.SMTP_SSL('smtp.gmail.com', 465)
smtpObj.login("sample#gmail.com","samplepassword")
for i in range(3):
smtpObj.sendmail(sender, receivers, message)
print("Successfully sent email")

The immediate problem is that your message is indented; a valid SMTP message contains two literal adjacent newlines to demarcate the headers from the body.
While you can assemble simple email messages from ASCII strings, this is not tenable for real-world modern email messages. You really want to use the email library (or a higher level third-party wrapper or replacement) to handle all the corner cases of email message encapsulation, especially if you are not an expert on email and MIME yourself.

Related

Python smtplib.SMTPRecipientsRefused

I been trying to make a python program that sends email but i keep getting this error
Traceback (most recent call last):
File "C:\Users\25194\PycharmProjects\Gmail\Yo.py", line 25, in <module>
smtp.sendmail(email_sender, email_password, em.as_string())
File "C:\Users\25194\AppData\Local\Programs\Python\Python310\lib\smtplib.py", line 901, in sendmail
raise SMTPRecipientsRefused(senderrs)
smtplib.SMTPRecipientsRefused: {'google login': (553, b'5.1.3 The recipient address <Gmail app password> is not a valid RFC-5321\n5.1.3 address. Learn more at\n5.1.3 https://support.google.com/mail/answer/6596 k9-20020a7bc409000000b003c6bd91caa5sm17184983wmi.17 - gsmtp')}
The code is
from email.message import EmailMessage
import ssl
import smtplib
email_sender = 'oropyt32#gmail.com'
email_password = 'google login'
email_reciver = 'milkiwasihunpro#gmail.com'
subject = 'Check mate'
body = """
I am making this sending this isnt it cool oro
"""
em = EmailMessage()
em['From'] = email_sender
em['TO'] = email_reciver
em['Subject'] = subject
em.set_content(body)
context = ssl.create_default_context()
with smtplib.SMTP_SSL('smtp.gmail.com', 465, context=context) as smtp:
smtp.login(email_sender, email_password)
smtp.sendmail(email_sender, email_password, em.as_string())
i am having hard time figuring out how to fix it
... b'5.1.3 The recipient address is not a valid RFC-5321\n5.1.3 address. ...
Obviously you are using a password in place where an email is expected
smtp.sendmail(email_sender, email_password, em.as_string())
From the documentation of sendmail:
SMTP.sendmail(from_addr, to_addrs, msg, mail_options=(), rcpt_options=())
So you give the email_password where to_addrs is expected. No wonder that it complains about your password used as recipient. You probably meant to use email_reciver instead.

Sending Mass Customized Emails Best Practices?

I have a flask app on PythonAnywhere that sends emails on a daily basis.
What is the best practice for customizing these? I need to add a unique token to the 'unsubscribe' link so I update the user's settings.
Is the best solution to simply loop through and manually merge the token with each template?
Are there any more efficient ways to do this? I don't have problems with this method but it doesn't seems scalable. Previously I could send bulk messages by using large BCC lists. I couldn't find any best practices for doing this manually, all solutions pointed towards a mail service.
Could I dynamically generate a token when 'unsubscribe' is clicked using embedded JavaScript referencing the user's address from the email headers?
recipients = ['email1#test.com', 'email2#test.com']
tokens = [token1, token2]
with smtplib.SMTP('smtp.gmail.com', 587) as smtp:
smtp.ehlo()
smtp.starttls()
smtp.ehlo()
smtp.login(EMAIL_ADDRESS, PASSWORD)
msg = EmailMessage()
for i in range(len(recipients)):
# Create the body of the message (a plain-text and an HTML version).
msg = MIMEMultipart('alternative')
msg['Subject'] = 'Your Daily Email'
msg['From'] = EMAIL_ADDRESS
msg['To'] = recipients[i]
with open('utils/email_template.html') as f:
html = f.read()
html = html.replace("{{token}}", token[i])
# Record the MIME types of both parts - text/plain and text/html.
part1 = MIMEText(text, 'plain')
part2 = MIMEText(html, 'html')
# Attach parts into message container.
# According to RFC 2046, the last part of a multipart message, in this case
# the HTML message, is best and preferred.
msg.attach(part1)
msg.attach(part2)
# Send the message via local SMTP server.
smtp.sendmail(EMAIL_ADDRESS, recipient[i], msg.as_string())

Gmail account. Python 3.8 idle script. Error: smtplib.SMTPSenderRefused: (503, b'5.5.1 EHLO/HELO first

I'm doing an exercise on writing a module in python 3.8 idle (Mac) to send emails from my gmail account. It is giving me the error:
smtplib.SMTPSenderRefused: (503, b'5.5.1 EHLO/HELO first.
THE COMPLETE RUNNING RESULT:
= RESTART: /Users/mimikatz/Desktop/python/Python_note&exercise/send_email_gmail.py
person_name
Thank you for sharing!
Traceback (most recent call last):
File "/Users/mimikatz/Desktop/python/Python_note&exercise/send_email_gmail.py", line 58, in <module>
main()
File "/Users/mimikatz/Desktop/python/Python_note&exercise/send_email_gmail.py", line 51, in main
s.send_message(msg)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/smtplib.py", line 970, in send_message
return self.sendmail(from_addr, to_addrs, flatmsg, mail_options,
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/smtplib.py", line 871, in sendmail
raise SMTPSenderRefused(code, resp, from_addr)
smtplib.SMTPSenderRefused: (503, b'5.5.1 EHLO/HELO first. c18sm12642612wmk.18 - gsmtp', 'xxxxx#gmail.com')
The first two lines (person_name Thank you for sharing!) are from the 'message.txt' file.
MY CODE IS:
import smtplib
from string import Template
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from_addr = 'xxxxxg#gmail.com'
password = 'xxxxxxxxxxx'
smtp_server = 'smtp.gmail.com'
def get_contacts(self):
names = []
emails = []
with open(self, 'r', encoding='utf-8') as contacts_file:
for a_contact in contacts_file:
names.append(a_contact.split()[0])
emails.append(a_contact.split()[1])
return names, emails
def read_template(self):
with open(self, 'r', encoding='utf-8') as template_file:
template_file_content = template_file.read()
return Template(template_file_content)
def main():
names, emails = get_contacts('contacts.txt') # read contacts
message_template = read_template('message.txt')
# set up the SMTP server
s = smtplib.SMTP_SSL(smtp_server)
s.ehlo()
s.connect(smtp_server,465)
s.login(from_addr, password)
# For each contact, send the email:
for name, email in zip(names, emails):
msg = MIMEMultipart() # create a message
# add in the actual person name to the message template
message = message_template.substitute(person_name = name.title())
# prints out the message body for our sake
print(message)
# setup the parameters of the message
msg['From'] = from_addr
msg['To'] = email
msg['Subject'] = 'This is TEST'
# add in the message body
msg.attach(MIMEText(message, 'plain', 'utf-8'))
# send the message via the server set up earlier.
s.send_message(msg)
del msg
# Terminate the SMTP session and close the connection
s.quit()
if __name__ == '__main__':
main()
I saw this code in one of the questions asked here and it looked great to me as an example, so I wanted to try it out. But my problem turns out different than what the original one had. From the running result, it looks like the """print(message)""" command is successfully loaded. The problem occurs at """s.send_message(msg)""". I checked online several similar cases but couldn't find answer that suits this condition.
Really grateful to any help :)
Acorus
Problem solved thanks to Konrad
Swapping the .ehlo() with .connect()
& Changing the password to an authentication code generated from gmail setting 2-step verification app password. I used "mail" & "mac" to generate the verification code.
While I have never used Python to send emails, I've spent some time communicating with SMTP servers via Telnet.
You need to connect to the server first, then send EHLO, then authenticate and finally send the message. Your code seems to try sending EHLO before connecting to the server.
Try swapping those two lines.

Sending mail with Python's smtplib returns "501 5.1.3 Invalid address"

Consider this code extract:
import smtplib
from email.message import EmailMessage
body = "some content"
email = EmailMessage()
email.set_content(body, subtype='html')
to = "you#work.com"
email['From'] = "me#work.com"
email['To'] = to
email['Cc'] = ""
email['Bcc'] = ""
email['Subject'] = "Hello"
smtp_connection = smtplib.SMTP("smtp.work.com", 25)
status = smtp_connection.send_message(email)
print(str(status))
print(to)
When running the code, the mail actually arrives correctly at the destination, but the print statement returns this: {'': (501, b'5.1.3 Invalid address')}
I've seen other posts around on the internet with similar error message, where it's been a case of malformed recipient addresses causing the message not to be delivered, but in my case the emails actually do get delivered correctly. I've also made sure that the email address output'ed by the last print statement is actually correct.
Any input on how to debug this further will be appreciated.
I believe I found the answer. Looks like empty "CC" and "BCC" values causes the error. When I removed these I got rid of the error message.
If your Cc and Bcc is also empty, it is no need to attach it in email[]

twilio/python/flask: Timeouts for TWIMLET-implemented voice mail?

I'm using a python3 flask REST-ful application to control my twilio-based phone services. Everything is working very well, but I have a question for which I haven't been able to find an answer.
When I want to redirect a caller to voicemail, I call the following voice_mail function from my REST interface, and I manage the voicemail via a twimlet, as follows ...
def voice_mail():
vmbase = 'http://twimlets.com/voicemail?Email=USER#DOMAIN.COM&Transcribe=False'
vmurl = '... URL pointing to an mp3 with my voicemail greeting ...'
return redirect(
'{}&Message={}'.format(vmbase, vmurl),
302
)
This works fine, but there doesn't seem to be any way to control how long the caller's voicemail message can last. I'd like to put an upper limit on that duration.
Is there any way via this twimlet (or perhaps a different twimlet) to force the voicemail recording to be cut off after a configurable amount of time?
If not, is there a default maximum duration of this twimlet-based voicemail recording?
And if neither of these are available, can someone point me to a python-based way of using other twilio features to ...
Route the caller to voice mail
Play a specified recording
Capture the caller's message.
Cut off the caller's recording after a configurable number of seconds.
Email a notification of the call and the URL of the recorded message to a specified email address.
I know that the existing twimlet performs items 1, 2, 3, and 5, but I don't know how to implement item 4.
Thank you.
Given that the voicemail twimlet doesn't allow a recording time limit to be specified, I was able to solve this without a twimlet in the following manner. And the sending of email turns out to be simple via the flask_mail package.
The following code fragments show how I did it ...
import phonenumbers
from flask import Flask, request, Response, url_for, send_file
from flask_mail import Mail, Message
app = Flask(__name__)
mail_settings = {
'MAIL_SERVER' : 'mailserver.example.com',
'MAIL_PORT' : 587,
'MAIL_USE_TLS' : False,
'MAIL_USE_SSL' : False,
'MAIL_USERNAME' : 'USERNAME',
'MAIL_PASSWORD' : 'PASSWORD'
}
app.config.update(mail_settings)
email = Mail(app)
# ... etc. ...
def voice_mail():
vmurl = '... URL pointing to an mp3 with my voicemail greeting ...'
resp = VoiceResponse()
resp.play(vmurl, loop=1)
resp.record(
timeout=5,
action=url_for('vmdone'),
method='GET',
maxLength=30, # maximum recording length
playBeep=True
)
return Response(str(resp), 200, mimetype='application/xml')
#app.route('/vmdone', methods=['GET', 'POST'])
def vmdone():
resp = VoiceResponse()
rcvurl = request.args.get('RecordingUrl', None)
rcvtime = request.args.get('RecordingDuration', None)
rcvfrom = request.args.get('From', None)
if not rcvurl or not rcvtime or not rcvfrom:
resp.hangup()
return Response(str(resp), 200, mimetype='application/xml')
rcvurl = '{}.mp3'.format(rcvurl)
rcvfrom = phonenumbers.format_number(
phonenumbers.parse(rcvfrom, None),
phonenumbers.PhoneNumberFormat.NATIONAL
)
msg = Message(
'Voicemail',
sender='sender#example.com',
recipients=['recipient#example.com']
)
msg.html = '''
<html>
<body>
<p>Voicemail from {0}</p>
<p>Duration: {1} sec</p>
<p>Message: {2}</p>
</body>
</html>
'''.format(rcvfrom, rcvtime, rcvurl)
email.send(msg)
return Response(str(resp), 200, mimetype='application/xml')
Also, it would be nice if someone could add a parameter to the voicemail twimlet for specifying the maximum recording duration. It should be as simple as using that parameter's value for setting maxLength in the arguments to the record() verb.
If someone could point me to the twimlets source code, I'm willing to write that logic, myself.

Resources