Forums

can't use smtplib to send emails anymore

[admin update 2013-10-28: see the wiki section on email/smtp]

I used to be able to use smtplib to send emails with my program, but it's not connecting to the network anymore. This is the basic code

import smtplib
user = mygmail@gmail.com
password = mypassword
smtpserv="smtp.gmail.com:587"
mailserver=smtplib.SMTP(smtpserv)
mailserver.starttls()
mailserver.login(user,password)
mailserver.sendmail(user,tolist,message)

pythonanywhere breaks it at the mailserver=smtplib.SMTP(smtpserv). This works fine on my computer

This is the error I get:

>>> mailserver = smtplib.SMTP(smtpserv)                                                                                                                                                                                                    
Traceback (most recent call last):                                                                                                                                                                                                         
  File "<stdin>", line 1, in <module>                                                                                                                                                                                                      
  File "/usr/local/lib/python3.3/smtplib.py", line 238, in __init__                                                                                                                                                                        
    (code, msg) = self.connect(host, port)                                                                                                                                                                                                 
  File "/usr/local/lib/python3.3/smtplib.py", line 317, in connect                                                                                                                                                                         
    self.sock = self._get_socket(host, port, self.timeout)                                                                                                                                                                                 
  File "/usr/local/lib/python3.3/smtplib.py", line 288, in _get_socket                                                                                                                                                                     
    self.source_address)                                                                                                                                                                                                                   
  File "/usr/local/lib/python3.3/socket.py", line 424, in create_connection                                                                                                                                                                
    raise err                                                                                                                                                                                                                              
  File "/usr/local/lib/python3.3/socket.py", line 415, in create_connection                                                                                                                                                                
    sock.connect(sa)                                                                                                                                                                                                                       
OSError: [Errno 101] Network is unreachable

The problem was fixed when I upgraded but I would still like this to work when I'm not paying

Looking into this...

Just a quick note to say that it looks like Harry's found the source of the problem -- he's fixing it now.

OK, I think I've figured out what happened. We only whitelist 1 of google's SMTP servers, but they round-robin around several, so when that changes, our iptables rule is out of date.

We'll see if we can't figure out a long-term solution...

Yes, this seems to cause a lot of people problems. Using multi-A records in DNS for load-balancing and fault tolerance is a brilliant idea (at my previous employer we used it extensively), but it does tend to cause all sorts of complications for clients which aren't written with it in mind.

For example, everyone should be using getaddrinfo() to do DNS lookups these days (because it supports multiple records and IPv6), but lots of people still fall back on the obsolete gethostbyname(). Even when people use the correct function, many of them write code which blindly connects to the first applicable result and bombs out with an error if it fails (instead of the more robust behaviour of trying each address in turn with a suitably short timeout until a connection is successfully established).

Anyway, as a short-term workaround you could fairly easily write some Python code which does a DNS lookup of your whitelist hosts (with getaddrinfo()) and yields the resultant IP addresses. You could render this into a script suitable for iptables-restore (with the -n option to avoid flushing old rules) so that you can apply an atomic update which removes the old rules and adds the new ones. If you're cunning about it you can diff the old and new sets so you only need to apply an update if there are any changes - adding comments to rules (with --comment) might make it easier to group the rules into those which originated from a given whitelisted hostname, or you could just keep an offline record and rely on nothing else screwing with the rules in the meantime.

See this blog post for more details of doing atomic iptables updates.

Instead of getaddrinfo() you could instead do a raw DNS lookup (either with dnspython or subprocess and host -a) and then you'd get hostnames instead of IP addresses. Personally I like to set up iptables rules with IP addresses, however, because it removes some of the unknowns from the equation when you're tracking down problems (such as the fact that the hostname is, as far as I'm aware, only re-resolved when the rules are reloaded).

EDIT

Re-reading that I should probably point out that when I use phrases like "fairly easily", that means fairly easy in principle as opposed to this'll take you 5 minutes. I wouldn't want anybody to think I was trivialising the effort involved, although I'd be quite surprised if it was more than a day's work to get a basic solution going - depends the difficulty of updating iptables rules on all the machines, among other things. Of course, that's a day that could be spent doing any number of other funky things. (^_^)

Exactly! The problem is that iptables configuration rules only take IP addresses; you can specify a host by name in the command, but it's resolved when you run it and the stuff stored in the iptables database only has the IP address. This makes perfect sense, of course -- every packet going into and out of the system is going to be matched against one or more iptables rules, and the last thing you want is a DNS lookup for every packet...

So what we think we could do is a script that ran periodically on every machine in the cluster that runs our users' code, and find out if the IP we're seeing for Google's SMTP servers is in the iptables whitelist, and add it if not. Which is definitely doable, but possibly a bit fiddly.

Have there been any updates to this issue? I've just started a project and I'm seeing this same error. When I send mail through gmail I get a socket exception '[Errno 101] Network is unreachable'.

I only see this problem sometimes. For 10-30 minutes, mail will work perfectly fine every time, and then I'll hit a period or 10-30 minutes when no emails will go through whatsoever.

I'm new to a lot of this, so I don't know if this should help, but I tried iterating through all the IP addresses returned by getaddrinfo, so rather than calling:
session = smtplib.SMTP( 'smtp.gmail.com', 587)

I tried something to the effect of: for addr_info in socket.getaddrinfo ( 'smtp.gmail.com', 587): session = smtplib.SMTP( addr_info[4][0], 587 )

Unfortunately, this doesn't seem to fix the issue. It just takes a bit longer to fail now.

Any hope to get this working?

@bccbrendan: Welcome to PythonAnywhere (PA)...☺

Hi bccbrendan,

Giles explanation still stands. We haven't scheduled any time to get this fixed right now. Like he said, it would be fiddly. You could always upgrade to Hacker account and bypass the firewall entirely...

Hi everyone,

I'm very new in webdev (iptables what?) and I've been loving pythonanywhere for testing my app and slowly getting to know how things work. I want to test if my django app's registration/password change etc routines work and so I've been trying to configure email sending (I get the error: [Errno 101] Network is unreachable), which brought me against a big wall of "I have no idea what these guys are talking about' as I've been reading through the threads about this issue.

Can someone please explain, or point me towards the right direction, about how to (hopefully quickly) manage to send emails through my django app in PA? Is it even worth the trouble? Im not going to stay behind this firewall forever so I don't want to spend too much time for a simple test.. Maybe I should set up apache in my local machine and test it there?

In Cartroo's post, I can follow up until this point "You could render this into a script suitable for iptables-restore (with the -n option to avoid flushing old rules) so that you can apply an atomic update which removes the old rules and adds the new ones" Ok, I get a list of whitelisted IPS, but then I don't get what I'm supposed to do with them.

Hi fifnir,

What server are you trying to use to send your email? The gmail smtp? Something else? On the other hand if you just want to test that it will work with unrestricted internet access then drop us a line at support@pythonanywhere.com and I might be able to help you out...

We are already August. Did you guys manage to fix this problem?

If you are having a problem connecting to gmail's smtp servers you can try upgrading your account. We poke holes in our firewall for Google's SMTP servers as a courtesy to free users but Google is so large and uses round robin DNS so we can't always guarantee that we've opened up the right IP addresses.

I use lot of google api in my python script and I have purchased startup plan for $99 my script is not working on pythonanywhere which is working fine on my local machine ERROR: error: [Errno 101] Network is unreachable

Please help me ASAP.

Hi Ashish,

I see that you just upgraded. You may have to restart your console window for the changes to take effect.

Conrad

Hi Conrad,

I'm experiencing the same "unreliable" problem with Google mail on my upgraded account. Some emails get sent out and some don't. Please help!

If you're getting an error when you send the email, what is it?

If you're not getting an error when you send the mail, then it is being sent, but there may be reasons why the emails are not delivered. That is not something that we can help with, it is something that you will need to contact Google about.