Search code examples
pythonflasktwiliopythonanywhere

Using Flask, Twilio API with PythonAnywhere gets error 11200 - HTTP retrieval failure


I made a flask app which detects messages received on whatsapp using Twilio Webhooks. After receiving a message, the app sends a message back to the same phone number. This works perfectly using Flask and Ngrok to deploy the server and expose it. Once I deploy it to PythonAnywhere however, I get a 11200 error in the Twilio console. Here's the code.

from flask import Flask, request
import requests
from twilio.rest import Client

account_sid = 'xxxxx'
auth_token = 'xxxxx'
client = Client(account_sid, auth_token)

def mmsg(phono, body):

    message = client.messages.create(
        from_='whatsapp:+14155238886',
        body=body,
        to=phono,
    )

app = Flask(__name__)

@app.route('/post', methods=['POST'])
def bot():
        incoming_msg = request.values.get('Body', '').lower()
        phono = request.values.get('From', "")
        if incoming_msg == 'hi':
            mmsg(phono, 'hello!')

if __name__ == '__main__':
    app.run()

When I check the PythonAnywhere error logs, I get this

2020-07-19 13:50:46,569: POST Request: https://api.twilio.com/2010-04-01/Accounts/AC84a8b5837227246efc0c6f9440b6e12c/Messages.json
2020-07-19 13:50:46,570: PAYLOAD: {'To': 'whatsapp:{myphonenumber}', 'From': 'whatsapp:+14155238886', 'Body': 'hello!'}
2020-07-19 13:50:49,576: Exception on /post [POST]
Traceback (most recent call last):
requests.exceptions.ConnectionError: HTTPSConnectionPool(host='api.twilio.com', port=443): Max retries exceeded with url: /2010-04-01/Accounts/AC84a8b5837227246efc0c6f9440b6e12c/Messages.json (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x7fc0504362e8>: Failed to establish a new connection: [Errno 111] Connection refused',))

I have tried adding another key and value to the message = client.messages.create like this.

message = client.messages.create(
            from_='whatsapp:+14155238886',
            body=item,
            to=phono,
            AC84a8b5837227246efc0c6f9440b6e12c='83ce0b901ff353f9b9a77222e001d71d'
        )

When I try that, I get this error on PythonAnywhere.

2020-07-19 14:09:51,030: Exception on /post [POST]
Traceback (most recent call last):
  File "/home/AbhayAysola/.virtualenvs/my-virtualenv/lib/python3.6/site-packages/flask/app.py", line 2447, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/AbhayAysola/.virtualenvs/my-virtualenv/lib/python3.6/site-packages/flask/app.py", line 1952, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/AbhayAysola/.virtualenvs/my-virtualenv/lib/python3.6/site-packages/flask/app.py", line 1821, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/home/AbhayAysola/.virtualenvs/my-virtualenv/lib/python3.6/site-packages/flask/_compat.py", line 39, in reraise
    raise value
  File "/home/AbhayAysola/.virtualenvs/my-virtualenv/lib/python3.6/site-packages/flask/app.py", line 1950, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/AbhayAysola/.virtualenvs/my-virtualenv/lib/python3.6/site-packages/flask/app.py", line 1936, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/home/AbhayAysola/bot.py", line 46, in bot
    mmsg(phono, ou)
  File "/home/AbhayAysola/bot.py", line 24, in mmsg
    AC84a8b5837227246efc0c6f9440b6e12c='83ce0b901ff353f9b9a77222e001d71d'
TypeError: create() got an unexpected keyword argument 'AC84a8b5837227246efc0c6f9440b6e12c'

Solution

  • Free accounts on PythonAnywhere have restricted Internet access; you can only access a specific set of sites (listed here, but this is a list of sites that you can access, not a list of sites that you can't access), and you have to use a proxy server to access them.

    For most libraries that is completely transparent -- they pick up the proxy settings from the system environment and use it without you having to do anything extra. But the Twilio library needs a little bit of extra configuration. There's a help page explaining what this is here, but the specific change to your code would be to replace this:

    client = Client(account_sid, auth_token)
    

    ...with this:

    import os
    from twilio.http.http_client import TwilioHttpClient
    
    proxy_client = TwilioHttpClient(proxy={'http': os.environ['http_proxy'], 'https': os.environ['https_proxy']})
    client = Client(account_sid, auth_token, http_client=proxy_client)