I tried to code a simple sms chatbot using Twilio & Flask. The code runs fine, and the console connects, but Twilio doesn't. Some website also said something about ngrok? When I text the Twilio phone number it says, "Thanks for the message. Configure your number's SMS URL to change this message. Cheers, Londo.
try:
from flask import Flask, request
import requests
from twilio.twiml.messaging_response import MessagingResponse
import datetime
except ModuleNotFoundError:
from subprocess import call
modules = ["flask","datetime"]
call("pip install " + ' '.join(modules), shell=True)
app = Flask(__name__)
x = datetime.datetime.now()
#app.route('/bot', methods=['POST'])
def bot():
incoming_msg = request.values.get('Body', '').lower()
resp = MessagingResponse()
msg = resp.message()
responded = False
if 'Hi' in incoming_msg:
msg.body("Hello Londo! *Type: 'Yo*")
responded = True
if 'Yo' in incoming_msg:
msg.body(f'Good morning!, the date is {x.strftime("%X")}. *Type: I am up*')
responded = True
if 'I am up' in incoming_msg:
msg.body('Do 10 pushups and 5 pullups! *Type: Done*')
responded = True
if 'Done' in incoming_msg:
msg.body('Now make the bed. *Type: Ok')
responded = True
if 'Ok' in incoming_msg:
msg.body('Wake TF up!')
responded = True
if not responded:
msg.body('I only respond to certian commands')
return str(resp)
if __name__ == '__main__':
app.run()
You need two things here.
First, you need your application to have a publicly accessible URL. Using ngrok is one way to achieve that, though there are others. To do so, download and install ngrok, then run ngrok http PORT where PORT is the port number your application is running on. When you do this, ngrok will give you a URL which your application is now available on.
Second, you need to configure your Twilio phone number with this URL. Open the Twilio console, navigate to your number and configure it. In the messaging section, add your URL (https://RANDOM_SUBDOMAIN.ngrok.io/bot) to the field for the webhook when you receive a message. Save the number and text it again, you should be good.
Do note that every time you start ngrok you will get a different subdomain, so you may have to update your number again. You can overcome this by paying for an ngrok account that allows for you to choose a subdomain, or by using the Twilio CLI to create the proxy to your localhost.
Related
I am trying to create a connection to whatsapp and my python script via Twilio, to generate automatic conversations. I follow every step in order of this link https://www.pragnakalp.com/create-whatsapp-bot-with-twilio-using-python-tutorial-with-examples/?unapproved=4864&moderation-hash=3861b2bc00104a39b5f3211076dda854#comment-4864
The problem arrays when I start a conversation with the bot, that in my ngrok port, ngrok http 5000 it says POST/ 403 Forbidden, in the section of https requests.
Before sending the message to the bot I run my python script:
from flask import Flask, request
from twilio.twiml.messaging_response import MessagingResponse
app = Flask(__name__)
##app.route("/wa")
#def wa_hello():
# return "Hello, World!"
#app.route("/wasms", methods=['POST'])
def wa_sms_reply():
"""Respond to incoming calls with a simple text message."""
# Fetch the message
msg = request.form.get('Body').lower() # Reading the message from the whatsapp
print("msg-->", msg)
resp = MessagingResponse()
reply = resp.message()
# Create reply
if msg == "hi":
reply.body("hello!")
return str(resp)
if __name__ == "__main__":
app.run(debug=True)
I tried running commands like ngrok http https://localhost:5000, turning off firewalls on my Mac, allowing my country on the Twilio´s web page, inserting config.hosts << /.*\.ngrok\.io/ in my terminal and restaring my laptop, config.hosts << "a0000000.ngrok.io" and skip_before_action :verify_authenticity_token but nothing of this work for me. The error os shown here:enter image description here
I have a python script with flask incorporated running on a RaspberryPi. This is set to trigger a wakeonlan script when IFTTT sends the appropriate POST webhook. Since I've turned it on I've been getting a LOT of random webhooks from random IPs. Obviously, they all get a 404 error as nothing else is active, but it still concerns me a bit.
Is there a way to make flask ignore (just completely not respond) to any webhooks that aren't the specific one (a POST to /post) I'm looking for? I've tried screwing with the return line, but then flask throws an error saying "View function did not return a response" and returns an error 500.
Is this even possible?
#!/usr/bin/env python3
from flask import Flask, request
from wakeonlan import send_magic_packet
from datetime import datetime
app = Flask(__name__)
dt = datetime.now()
print("WakeOnLan started at: ", dt)
#app.route('/post', methods= ["POST"])
def post():
print("POST received at: ", dt)
body = request.get_data(as_text=True)
if body == "desktop":
send_magic_packet('XX.XX.XX.XX.XX.XX')
print("Magic Packet sent to", body, "at:", dt)
return ''
#Router forwards port 80 to 30000 on the pi
app.run(host='0.0.0.0', port = 30000)
Following the Twilio SMS Python Quickstart guide found here:
https://www.twilio.com/docs/sms/quickstart/python
I can get up to the "Receive and reply to inbound SMS messages with Flask" section perfectly fine, with both my http://localhost:5000/ and ngrok URL showing the correct "Hello World" message.
However, as soon as I replace the run.py file code with the instructed code to reply to the sender with an sms, both URLs become dead with a "404 Not Found" error.
Have tried restarting everything etc.
run.py:
# /usr/bin/env python
# Download the twilio-python library from twilio.com/docs/libraries/python
from flask import Flask, request
from twilio.twiml.messaging_response import MessagingResponse
app = Flask(__name__)
#app.route("/sms", methods=['GET', 'POST'])
def sms_ahoy_reply():
"""Respond to incoming messages with a friendly SMS."""
# Start our response
resp = MessagingResponse()
# Add a message
resp.message("Ahoy! Thanks so much for your message.")
return str(resp)
if __name__ == "__main__":
app.run(debug=True)
Any ideas?
As soon as I change the run.py code back to the original "Hello World" code both URLs run fine.
Also, the ngrok server does show an attempted connection when I send an sms message to the twilio number too, but with a "404 Not Found" message next to it.
I have faced the following problem after moving my bot to the new server. I use webhook to get updates but now the bot does not get them from telegram servers. I tried to send POST request with curl from the remove server and bot handled it in a normal way. I checked webhook with getWebhookInfo and it returned an object with non-empty url and pending_update_count equal to 74 without errors. I guess, it means that telegram servers are not able to send POST request to my host for some reason.
OS of my server is Arch Linux.
I use pyTelegramBotAP.
CONFIG = ConfigParser()
CONFIG.read(os.path.join('data', 'config.ini'))
# webhook url
URL_BASE = "https://{}:{}".format(CONFIG['server']['ip'], CONFIG.getint('server', 'port'))
URL_PATH = "/{}/".format(CONFIG['telegram bot']['token'])
BOT = telebot.TeleBot(CONFIG['telegram bot']['token'])
# server that will listen for new messages
APP = web.Application()
URL = URL_BASE + URL_PATH
BOT.set_webhook(url=URL, certificate=open(CONFIG['ssl']['certificate'], 'rb'))
# Build ssl context
CONTEXT = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
CONTEXT.load_cert_chain(CONFIG['ssl']['certificate'], CONFIG['ssl']['private key'])
# Start aiohttp server
web.run_app(
APP,
host=CONFIG['server']['listen'],
port=CONFIG['server']['port'],
ssl_context=CONTEXT,
)
Please, help!
Telegram webhook only talks to https endpoints, so I suggest to check your server against https connections.
Also, getWebhookInfo call returns a status object with the latest error infomation of your endpoint. Have a look of that error info and might find the exact problem.
Please check the Firewall on your server, It is quite possible firewall on your server is not passing message to your application.
To check firewall status run $ ufw status
Please show you URL_BASE without real IP.
What operating system is on your server?
You send test request from the CURL to URL of the Telegram or of your server?
Can you getting response from your server if you run simple app?
Example:
from aiohttp import web
async def hello(request):
return web.Response(text='Hello world!')
app = web.Application()
app.add_routes([web.get('/', hello)])
web.run_app(app, host='localhost', port=3003)
Check response:
$ curl localhost:3003
Hello world!
Please provide more detailed information on how you troubleshoot.
I'm testing the Instagram Real-time API with Python and Flask and I get everytime this response from the Instagram server:
{
"meta":{
"error_type":"APISubscriptionError",
"code":400,
"error_message":"Unable to reach callback URL \"http:\/\/my_callback_url:8543\/instagram\"."
}
}
The request:
curl -F 'client_id=my_client_id...' \
-F 'client_secret=my_client_secret...' \
-F 'object=tag' \
-F 'aspect=media' \
-F 'object_id=fox' \
-F 'callback_url=http://my_callback_url:8543/instagram' \
https://api.instagram.com/v1/subscriptions/
And this is the code of the Flask server:
from flask import Flask
from flask import request
from instagram import subscriptions
app = Flask(__name__)
CLIENT_ID = "my_client_id..."
CLIENT_SECRET = "my_client_secret..."
def process_tag_update(update):
print 'Received a push: ', update
reactor = subscriptions.SubscriptionsReactor()
reactor.register_callback(subscriptions.SubscriptionType.TAG, process_tag_update)
#app.route('/instagram', methods=['GET'])
def handshake():
# GET method is used when validating the endpoint as per the Pubsubhubub protocol
mode = request.values.get('hub.mode')
challenge = request.values.get('hub.challenge')
verify_token = request.values.get('hub.verify_token')
if challenge:
return challenge
return 'It is not a valid challenge'
#app.route('/instagram', methods=['POST'])
def callback():
# POST event is used to for the events notifications
x_hub_signature = request.headers.get('X-Hub-Signature')
raw_response = request.data
try:
reactor.process(CLIENT_SECRET, raw_response, x_hub_signature)
except subscriptions.SubscriptionVerifyError:
print 'Signature mismatch'
return 'done'
def server():
""" Main server, will allow us to make it wsgi'able """
app.run(host='0.0.0.0', port=8543, debug=True)
if __name__ == '__main__':
server()
The machine have a public IP and the port is open for everyone. I can reach the url from others networks.
Why can't Instagram reach my url? Is there a black list or something like that?
Update 1
I have tested the same code with some frameworks and WSGI servers (Django, Flask, Node.js, Gunicorn, Apache) and different responses in the GET/POST endpoint and I always get the same 400 error message.
Also I have checked the packages received in my network interface with Wireshark and I get the expected results with calls from any network. But I don't get any package when I do the subscription request.
So... Is this a bug? Could be my IP in any blacklist for some reason?
I had exactly the same. It worked when I accidentally restarted the router, getting a different IP. It seems that it could be an IP issue indeed and the Unable to reach callback URL... is not really helpful in this case.
I agree, there are plenty of AWS servers answering to that API and some are not working. Ping api.instagram.com and you'll see you get multiple and different IP for that domain name. There is a DNS round robin and you are not reaching the same server every time.
I've found one server (IP : 52.6.133.72) which seems to be working for subscription and have configured my server to use that one (by editing the /etc/hosts file). Not a reliable solution ... but it's working.