I'm able to automate some emails internally using mime and smtplib, but for some reason, these emails fail to send to external addresses (outside of company's domain)
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email import Encoders
import smtplib
SERVER = 'mailrelay'
FROM = 'myemail#internaldomain.com'
TO = ['myemail#internaldomain.com','someemail#externaldomain.com']
body = 'This is a test'
msg = MIMEMultipart()
msg["To"] = ','.join(TO)
msg["From"] = FROM
msg["Subject"] = 'Automated Test Email'
msgText = MIMEText(body, 'html')
msg.attach(msgText)
message = msg.as_string()
server = smtplib.SMTP(SERVER)
server.sendmail(FROM,TO,message)
server.quit()
Produces this error:
SMTPRecipientsRefused: {'someemail#externaldomain.com': (550, '5.7.1 Unable to relay')}
Admin insists that relaying is enabled, and told me that sending emails to external domains using Powershell works, so it can't be a relay issue.
So now I'm stuck. If it's not the problem python is telling me it is, is my admin wrong or is something else going on?
Any ideas?
Looks like I just needed to authenticate in this case:
server.ehlo()
server.starttls()
server.ehlo
server.login('user', 'pass')
Related
I have been trying to create a web app which takes email address as an input through HTML form and sends a one time pin for further access to website.
I have 2 html files in my template folder (one for taking user's email address and other for OTP entering)
i have config.json file which stores my accountid and password through which i intend to send the OTP.
.py file
from flask import Flask, render_template, request
from random import randint
import json
from flask_mail import *
with open('config.json','r') as f:
params = json.load(f)['params']
mail = Mail(app)
otp = randint(100,999) #otp production
app.config['MAIL_SERVER'] = 'smtp.gmail.com'
app.config['MAIL_PORT'] = 465
app.config['MAIL_USE_TLS'] = False
app.config['MAIL_USE_SSL'] = True
app.config['MAIL_USERNAME'] = params['gmail-user']
app.config['MAIL_PASSWORD'] = params['gmail-password']
#app.route('/')
def home():
return(render_template('otpgive.html'))
#app.route('/getOTP', methods = ['POST'])
def getOTP(): #OTP send and Verify here
email_id = request.form['usermail']
msg = Message('OTP for the APPLICATION', sender = 'my_email', recipients = [email_id])
#my_email is the email through which i plan to send messages.
msg.body = "Greetings! Your email has been verified successfully. Kindly note your OTP is " + str(otp)
mail.send(msg)
return render_template('otpconfirm.html')
#app.route('/validateOTP', methods = ['POST'])
def validateOTP():
userotp = request.form['otp']
if (otp == int(userotp)):
return ("Email Verified Succcessfully ")
else:
return render_template('otpgive.html',msg = 'incorrect otp')
if __name__ == '__main__':
app.run(debug = False)
#app.run(host='0.0.0.0',port=5000, debug = True)
Solutions I tried but failed:
Tried disabling the firewall.
Tried setting the port number for 0.0.0.0
Tried debug = False
I was expecting it to work. i.e send emails to the users but it shows ConnectionError or InternalServerError
Internal Server Error
The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.
ConnectionRefusedError:
[WinError 10061] No connection could be made because the target machine actively refused it
I finally got the solution.
Since I was using G-Mail, I had to enable 2FA (2-Factor Auth) first on my profile, and then generate a new password for my app.
The password thus obtained was pasted in the config.json file instead of my
main profile password.
Used directions from this thread Less Secure option in gmail unavailable
Now Changes I made in my code:
Reverted back to ip: host='0.0.0.0', port=5000, debug = True
I kept firewall disabled as a precaution.
I repositioned mail = Mail(app) line to after all app.configs
I'm currently building an app which contains email sending to multiple users which i'm able to do but i want to add a functionality which schedule's an email, for instance I'm using sent_at method as you can see below:-
settings.py
EMAIL_FROM = 'EMAIL'
EMAIL_API_CLIENT ='XXXXXXXX'
views.py
import json
from sendgrid import SendGridAPIClient
from django.conf import settings
message = Mail(from_email=settings.EMAIL_FROM,
to_emails=selectedphone,
subject=subject,
html_content=editor)
message.extra_headers = {'X-SMTPAPI': json.dumps({'send_at':
FinalScheduleTime})}
sg = SendGridAPIClient(settings.EMAIL_API_CLIENT)
response = sg.send(message)
if response.status_code == 202:
emailstatus = "Accepted"
elif .....
else.....
I've also tried message.extra_headers = {'SendAt':FinalScheduleTime} but it's not working either.
Here the FinalScheduleTime is of the datetime object. The sendgrip api accepts the UNIX timestamp according to the documentation. You can check it here
Hence to convert your datetime object into unix time stamp, you can use the time module of python.
scheduleTime = int(time.mktime(FinalScheduleTime.timetuple()))
Also, replace the message.extra_headers with message.send_at.
Hence, your final code will look like:
import json
import time
from sendgrid import SendGridAPIClient
from django.conf import settings
message = Mail(from_email=settings.EMAIL_FROM,
to_emails=selectedphone,
subject=subject,
html_content=editor)
scheduleTime = int(time.mktime(FinalScheduleTime.timetuple()))
message.send_at = scheduleTime
sg = SendGridAPIClient(settings.EMAIL_API_CLIENT)
response = sg.send(message)
if response.status_code == 202:
emailstatus = "Accepted"
elif .....
else.....
This is an official blog by Twilio on Using Twilio SendGrid To Send Emails from Python Django Applications - https://www.twilio.com/blog/scheduled-emails-python-flask-twilio-sendgrid
Also here are, official docs
I tried sending an email using the SMTP (Python 2.7.9).
The sender I provide is 'kmuthukumar#example.com', however in the receiver's inbox, the sender is cut short into 'ukumar#example.com', which is another existing user in our system.
Any idea what is causing this?
More info:
This issue only happens when emails are generated by code using 'kmuthukumar' as sender. Results are normal when kmuthukumar sends an email through email applications. The original code is working fine for all other users.
import time
from smtplib import SMTP
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
server='internal-smtp.example.com'
sender="kmuthukumar#example.com"
recipients = ['user#example.com']
cc=[]
msg = MIMEMultipart()
msg["From"] = sender
msg["To"]=", ".join(recipients) if isinstance(recipients, list) else recipients
msg["Subject"] = "test"
msg['Date'] = time.ctime(time.time())
subtype='plain'
charset='utf-8'
message = "hello"
text = MIMEText(message, _subtype=subtype, _charset=charset)
msg.attach(text)
smtp = SMTP(server)
smtp.sendmail(sender, list(set(recipients+cc)), msg.as_string())
smtp.quit()
I want to sends an email but sent mail is empty.
how to send an email, and then put a copy of it in the "Sent" mail folder.
what can i do?
Yes, its possible.
Basicaly you need to create an MIME email and then send it throug smptlib and than save it on Sent with imaplib.
The official imaplib documentation.
More detailed examples of using imaplib.
Here is an example:
import time
import ssl
import imaplib
import smtplib
import email
from email import encoders
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
class Mail:
def __init__(self):
# considering the same user and pass for smtp an imap
self.mail_user = 'youruser#yourdomain.com'
self.mail_pass = 'pass'
self.mail_host = 'mail.yourdomain'
def send_email(self, to, subject, body, path, attach):
message = MIMEMultipart()
message["From"] = self.mail_user
message["To"] = to
message["Subject"] = subject
message.attach(MIMEText(body, "plain"))
with open(path + attach, "rb") as attachment:
part = MIMEBase("application", "octet-stream")
part.set_payload(attachment.read())
encoders.encode_base64(part)
part.add_header(
"Content-Disposition",
"attachment; filename= \"" + attach + "\"",
)
message.attach(part)
text = message.as_string()
context = ssl.create_default_context()
with smtplib.SMTP_SSL(self.mail_host, 465, context=context) as server:
result = server.login(self.mail_user, self.mail_pass)
server.sendmail(self.mail_user, to, text)
imap = imaplib.IMAP4_SSL(self.mail_host, 993)
imap.login(self.mail_user, self.mail_pass)
imap.append('INBOX.Sent', '\\Seen', imaplib.Time2Internaldate(time.time()), text.encode('utf8'))
imap.logout()
if __name__ == '__main__':
m = Mail()
m.send_email('someone#somewhere.com', 'Hello', 'Its just a test!', 'c:\\', 'test.pdf')
We are using ROBOT framework to execute automation test cases.
Could anyone please guide me to write script for e-mail notification of test results.
Note:
I have e-mail server details.
Regards,
-kranti
You can create a custom library for send email.
More details in official documentation
I did something similar, I based on this article to create the library.
an example of the function in python file:
import smtplib
from io import StringIO
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email import encoders
import os
def send_mail_no_attachment(server, from_user, from_password, to, subject, text):
msg = MIMEMultipart()
msg['From'] = from_user
msg['To'] = to
msg['Subject'] = subject
msg.attach(MIMEText(text))
mailServer = smtplib.SMTP(server)
mailServer.ehlo()
mailServer.starttls()
mailServer.ehlo()
mailServer.login(from_user, from_password)
mailServer.sendmail(from_user, to, msg.as_string())
mailServer.close()
call the function in robot file:
*** Test Cases ***
example mail
send mail no attachment ${SMTP_SERVER} ${USER} ${PASS} ${mail} ${subject} ${text}
If you are not very expert with the robot framework, define only the function, do not define the class, and you can call this function within your algorithm as a keyword.
I use smtplib and MIMEText
import smtplib
from email.mime.text import MIMEText
class EmailClient():
def __init__(self, my_address):
self.my_address = my_address
def send(self, message, subject, user, email):
header = "Hello " + str(user) + ",\n\n"
footer = "\n\n-Your Boss"
msg = MIMEText(header + message + footer)
msg['Subject'] = subject
msg['From'] = self.my_address
msg['To'] = email
s = smtplib.SMTP('localhost')
s.sendmail(self.my_address, [email], msg.as_string())
s.quit()
EClient = EmailClient("MyEmail#University.edu")
EClient.send("This is a test Email", "Test Subject", "John Doe", "jdoe#University.edu")
you can use jenkins to run your Robot Framework Testcases. There is a auto-generated mail option in jenkins to send mail with Test results.
I have similar requirement so using python file I have achieved requirement (need to execute .py file after robot execution)
Project link and Readme.md
How to send email after test execution
Copy robotemail.py to file
Create a bat file (which executes robot command and .py file in sequence)
robot test.robot &&
python robotemail.py
Execute bat file
Email will be sent to recipients