How to get the SMTP server response code in Django? - python

Goal:
Hi! How can I get the SMTP response codes through Django, similar to return values given from the smtplib module??? I want to use Django's api instead of having to use that, and I see nothing in Django's email docs.
I know send_mail(), send_mass_mail() , and EmailMessage.send_messages(...) all have return values that show the number of successfully delivered messages... But I want the response codes for all of them. The point is to get proof that an email is sent, bad email address, etc, like smtp response codes show.
And it's looking to me like I'd have to make a custom email backend for this, and subclass from BaseEmailBackend... It's using smtplib anyway.
Example code for smtplib's response code
import smtplib
obj = smtplib.SMTP('smtp.gmail.com', 587)
response = obj.ehlo()
print(response)
# Obviously this doesn't send a message yet, but I want response[0]
(250, b'smtp.gmail.com at your service, [111.222.33.44]\nSIZE 31234577\n8BITMIME\nSTARTTLS\nENHANCEDSTATUSCODES\nPIPELINING\nCHUNKING\nSMTPUTF8')

If you just want to check if mail is sent you can use return value of send_mail() function
The return value will be the number of successfully delivered messages
(which can be 0 or 1 since it can only send one message).
Django does catch smtplib errors and returns 0 if any error occurred or returns exception if fail_silently is false ( default true)
from django.core.mail.backends.smtp.EmailBackend source _send():
try:
self.connection.sendmail(from_email, recipients, message.as_bytes(linesep='\r\n'))
except smtplib.SMTPException:
if not self.fail_silently:
if not self.fail_silently:
raise
return False
return True
same thing on open()

Related

Getting key error while setting and getting cookie

I'm getting a weird exception while setting and getting the cookie in Django.
I'm getting key error while trying to print the cookie value. Could someone please tell me the reason by looking at the stack trace http://dpaste.com/3M3ZKXW
def sessionHandler(request):
userName = request.GET.get('uname')
response = HttpResponse("Setting the cookie now")
response.set_cookie('cookie_user_name', userName)
return JsonResponse({'Response': 'success'})
def login(request):
cookie_user = request.COOKIES['cookie_user_name']
print("################################")
print(cookie_user)
UserName = {"Name": global_user_name}
return render(request, 'login/login.html', UserName)
Exception Type: KeyError at /NewHandBook/welcome
Exception Value: 'cookie_user_name'
Why it's not working
You are setting the cookie on the response, so only the next request from the client after running through the middleware will have the cookie. With or without the middleware, this first request to the server from any client will never have this cookie set (or any other cookie).
Sidenote:
It's better to use failsafe code here: The login page should not break just because a GET parameter was not set, anyway. It shouldn't even return an error if this is the entry point to your site. I'm guessing you just want to display a nice "welcome back" message.
The way of your cookie is like this:
CLIENT: /login?uname=foobar
-> request w/o cookie
-> middleware sets *response* cookies
-> /login handler checks *request* cookies: None
The way of cookies in general is:
CLIENT: first request
-> server sets response cookies
-> server sends response (preferrably 2**)
CLIENT: displays response and stores cookies
CLIENT: next request with cookies
-> server reads cookies from request (e.g. session+CSRF cookies)
-> server sends response (again with cookies, CSRF-Token etc.)
How to make it work
Cookies are something that the server uses to check back with the client.
In your case you are already sending the info you want from the client via GET parameter. You don't need a cookie in this case, because this is not something you want the client to store but instead you want to process it on the server (and it has already reached the server).
Simplest solution to illustrate:
def login(request):
userName = request.GET.get('uname')
print("################################")
print(userName)
UserName = {"Name": userName}
return render(request, 'login/login.html', UserName)
So, you just need to find a way to store it in the middleware and read it back in the login handler. This is what the session is for. You have a session as soon as the first request comes in from the client (with Django).
The session lives through the login, and you will be able to access any data stored within it as long as the session lives (that is: as long as the session cookie is stored on the client and has not expired).
Make sure to add your middleware to the chain after Django's session middleware.
https://docs.djangoproject.com/en/2.2/topics/http/sessions/

How do I log into Google through python requests?

I'm making an API using Python requests, and HTTP GET is working fine, but I'm having a little bit of trouble with HTTP POST. So, as with a lot of websites, you can read information, but in order to make a post request (such as following a user, or writing a post), you need to have an authenticated session. THIS website, uses google to log in. Normally, I would just pass the username:password into the POST request formdata to log in, but this google thing is pretty wonky (and quite frankly I'm not that experienced). Does anyone have a reference or an example to help me out? ;/
I do not know about python requests but to send an email its as easy as this
import yagmail
yagmail.SMTP(emailh).send(email, subject, body)
#emailh = your email (just username no #gmail.com)
#email = send to (full email including domain ***#gmail.com or ***#outlook.com)
#subject = subject of the message
#body = body of the message
Even better
emailh = raw_input('Your email: ')
email = raw_input('Send to: ')
subject = raw_input('Subject: ')
body = raw_input('Body: ')
yagmail.SMTP(emailh).send(email, subject, body)
print('Email Sent.')
If this is what you are talking about anyway.
This page might be useful link

Python server.sendmail() returns {}. Email not sent

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?

sending emails in python weird behaviour

I am working on a piece of code that regularly sends emails from 4 different accounts, 2 of them are gmail accounts and the other 2 are yahoo accounts. When I started writing the code I was able to send all the emails from both the gmail accounts using the following piece of code:
def sendGmail(self, fromaddr, toaddr, username, password,
email_body, email_subject
):
# Build the email
msg = MIMEText(email_body)
msg['Subject'] = email_subject
msg['From'] = fromaddr
msg['To'] = toaddr
try:
# The actual mail send
server = smtplib.SMTP('smtp.gmail.com:587')
server.starttls()
server.login(username,password)
server.sendmail(fromaddr, toaddr, msg.as_string())
server.quit()
print "email sent: %s" % fromaddr
except Exception as e:
print "Something went wrong when sending the email %s" % fromaddr
print e
As I said, this piece of code worked perfectly, now that I add the sendYahoomail(), which is a different method, I always get (530, 'Access denied') as an exception for using sendGmail(). I'm pretty sure it's got nothing to do with my Yahoo method, and I can login from the browser with the gmail credentials correctly.
What can possibly be wrong, or just Gmail doesn't want me to send through code ?
I tried your code above with my Gmail account (actually it's a Google Apps account, but that should be identical) and it works fine for me. I even tried an incorrect "From" header and also using the incorrect source address at the SMTP level - both times Gmail allowed me to send the email, but seemed to quietly fix up the header on egress. Still, you might like to double-check your from address matches your username. Also try using the full email address as the username if you're currently just using the part before the #.
I also tried an incorrect password and received error 535, which isn't the same as what you're seeing. Since I have 2-factor authentication enabled I also tried my real password instead of an application-specific one and that still gave a 535 error (but with the message "application-specific password required").
Is it possible that your ISP has set up something that's intercepting SMTP connections to Gmail? Seems unlikely, although my ISP once blocked access to Gmail on port 587 although port 465 still worked. Perhaps you could try using smtplib.SMTP_SSL on port 465 just in case and see if that gives you any more joy.
You could also try sending to addresses at different providers in case Gmail is rejecting the send for that reason (e.g. if the other provider has been got on to a spam blacklist, for example). Also, if it's possible your email looks like spam, try you code with a message subject and body that's close to an authentic email and see if that helps.
You might find this helpful: https://support.google.com/mail/answer/14257
Basically, Google has detected an attempt to sign in from a server that it considers unfamiliar, and has blocked it. The link above lets you attempt to unblock it.
Sometimes it has worked for me, and sometimes not.

How do I get the response back from server after an email sending?

I want to get response from server with server status (eg. 200, 500) that says if message was delivered. How to do that?
>> s = smtplib.SMTP('...')
>> resp = s.sendmail('me#me.com', 'exist#email.com', 'message')
>> print resp
{}
>> resp = s.sendmail('me#me.com', 'does-not-exist-email#email.com', 'message')
>> print resp
{}
>> resp = s.sendmail('me#me.com', 'does-not-exist-domain#email000.com', 'message')
>> print resp
{}
o_O
Thanks.
You can't. SMTP does not support that behavior.
This is normal behavior of sendmail in case of successful sending. You can check this both in doc and smtp lib source. Empty dictionary as a response means that server accepted and sent message to each of recipients.
Regarding the status of delivery. SMPT protocol is simply unable to guaranty at this stage that message will be successfully delivered to the recipient. This means that first server may accept the message and push it forward, but one of the next mail-hop servers may simply drop it (for some reasons, of course, and first server will probably be informed about these reasons, but there is no possibility to inform you about all this stuff).
As they say about emailing - 'It is easy to send message, but it is much harder to get it delivered'.

Categories

Resources