How to check whether IMAP-IDLE works? - imap

I noticed that my IMAP server seems to support IDLE but notifications arrive late. So I was asking myself: How can I check whether IDLE works (or is it my mail client)?

Inspired by http://pymotw.com/2/imaplib/, you can use following Python scripts to check if and how fast push notification via IDLE work:
imaplib_connect.py
import imaplib
import ConfigParser
import os
def open_connection(verbose=False):
# Read the config file
config = ConfigParser.ConfigParser()
config.read([os.path.abspath('settings.ini')])
# Connect to the server
hostname = config.get('server', 'hostname')
if verbose: print 'Connecting to', hostname
connection = imaplib.IMAP4_SSL(hostname)
# Login to our account
username = config.get('account', 'username')
password = config.get('account', 'password')
if verbose: print 'Logging in as', username
connection.login(username, password)
return connection
if __name__ == '__main__':
c = open_connection(verbose=True)
try:
print c
finally:
c.logout()
print "logged out"
imaplib_idlewait.py
import imaplib
import pprint
import imaplib_connect
imaplib.Debug = 4
c = imaplib_connect.open_connection()
try:
c.select('INBOX', readonly=True)
c.send("%s IDLE\r\n"%(c._new_tag()))
print ">>> waiting for new mail..."
while True:
line = c.readline().strip();
if line.startswith('* BYE ') or (len(line) == 0):
print ">>> leaving..."
break
if line.endswith('EXISTS'):
print ">>> NEW MAIL ARRIVED!"
finally:
try:
print ">>> closing..."
c.close()
except:
pass
c.logout()
settings.ini
[server]
hostname: yourserver.com
[account]
username: yourmail#yourserver.com
password: yoursecretpassword
After creating those files, just call
python imaplib_idlewait.py
Please note, that this scripts does not close gracefully if you press CTRL+C (readline() is blocking and is not terminated by close()), however, for testing it should be good enough.
Also note, that most mail server terminate the connection after 30 minutes. After that you have to re-open the connection, e.g. like demonstrated here: http://blog.mister-muffin.de/2013/06/05/reliable-imap-synchronization-with-idle-support

Related

UMQTT.simple function to check client.ping() call back

I am trying to get my head around UMQTT.simple. I am looking to handle instances in which my server might disconnect for a reboot. I want to check whether the client is connected, and if not, wait some period and try to reconnect.The guidance seems to be to use client.ping() for this (How to check Micropython umqtt client is connected?).
For the MQTT.paho client I see there is a way to access ping responses in the logs function (see here: http://www.steves-internet-guide.com/mqtt-keep-alive-by-example/). For UMQTT the docs indicate that ping response is handled automatically by wait_msg(): Ping server (response is automatically handled by wait_msg() (https://mpython.readthedocs.io/en/master/library/mPython/umqtt.simple.html). There does not appear to be any analogous logs function mentioned in the UMQTT.simple docs.
This is confounding for a couple of reasons:
If i use client.wait_msg() how do I call client.ping()? client.wait_msg() is a blocking function, so I can't make the ping. The system just disconnects when the keepalive time is reached.
If I call client.check_msg(), and client.ping() intermittently, I can't access the callback. My callback function doesn't have parameters to access pingresponse (params are f(topic, msg) in the docs).
The way I am solving this for now is to set a bunch of try-except calls on my client.connect and then connect-subscribe functions, but its quite verbose. Is this the way to handle or can i take advantage of the pingresponse in UMQTT.simple?
Below is a sample of the code i am running:
#Set broker variables and login credentials
#Connect to the network
#write the subscribe call back
def sub_cb(topic, msg):
print((topic, msg))
#write a function that handles connecting and subscribing
def connect_and_subscribe():
global CLIENT_NAME, BROKER_IP, USER, PASSWORD, TOPIC
client = MQTTClient(client_id=CLIENT_NAME,
server=BROKER_IP,
user=USER,
password=PASSWORD,
keepalive=60)
client.set_callback(sub_cb)
client.connect()
client.subscribe(TOPIC)
print('Connected to MQTT broker at: %s, subscribed to %s topic' % (BROKER_IP, TOPIC))
return(client) #return the client so that i can do stuff with it
client = connect_and_subscribe()
#Check messages
now = time.time()
while True:
try:
client.check_msg()
except OSError as message_error: #except if disconnected and check_msg() fails
if message_error == -1:
time.sleep(30) #wait for reboot
try:
client = connect_and_subscribe() #Try connect again to the server
except OSError as connect_error: #If the server is still down
time.sleep(30) #wait and try again
try:
client = connect_and_subscribe()
except:
quit() #Quite so that i don't get stuck in a loop
time.sleep(0.1)
if time.time() - now > 80: #ping to keepalive (60 * 1.5)
client.ping()
now = time.time() #reset the timer

Authentication unsuccessful error with smtp.office365.com when using python3 smtplib

I have this python program that sends me daily emails. This is my personal email account with Microsoft outlook.com. My code has been working fine but broke yesterday. Here is my code
def email(subject, text):
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
user = "xxx#hotmail.com"
passwd = "xxxxxx"
sender = 'xxx#hotmail.com'
receiver = 'xxx#hotmail.com'
msg = MIMEMultipart('mixed')
msg['Subject'] = subject
msg['From'] = 'xxx#hotmail.com'
msg['To'] = 'xxx#hotmail.com'
text_plain = MIMEText(text,'plain','utf-8')
msg.attach(text_plain)
server = smtplib.SMTP('smtp.office365.com', 587)
server.ehlo()
server.starttls()
server.login(user, passwd)
server.sendmail(sender, receiver, msg.as_string())
server.quit()
User, sender, receiver, to and from are all the same email address. When I run the script, I got this error
>>> email('test subject', 'test message')
File "<stdin>", line 1, in <module>
File "<stdin>", line 19, in email
File "/usr/lib/python3.6/smtplib.py", line 730, in login
raise last_exception
File "/usr/lib/python3.6/smtplib.py", line 721, in login
initial_response_ok=initial_response_ok)
File "/usr/lib/python3.6/smtplib.py", line 642, in auth
raise SMTPAuthenticationError(code, resp)
smtplib.SMTPAuthenticationError: (535, b'5.7.3 Authentication unsuccessful [MW4PR03CA0229.namprd03.prod.outlook.com]')
Any ideas what could go wrong? This script has been working for at least half year..
Thanks!
Difan
not sure if I'll be of any help but since yesterday we are having problems with thunderbird connecting to microsoft mail server. For the base account changing authentication method to OAuth2 helped, but I still don't know what to do about aliases.
So I guess the problem lies with microsoft changing the requierements for authentication.

Twilio - Quick question (Unable to update record)

hope you are doing it right these days.
To summarize my problem, I think this is not working becuase I am using a free Twilio account instead of a paid one. But that's just my beginner theory. Now, the issue:
I have tried an official Twilio tutorial (https://www.twilio.com/blog/automating-ngrok-python-twilio-applications-pyngrok, I shared the link in case someone finds it interesting or needs it), which allows us to automate SMS webhook (sms_url) configuration by using Client (twilio) and pyngrok (ngrok).
def start_ngrok():
from twilio.rest import Client
from pyngrok import ngrok
url = ngrok.connect(5000)
print(' * Tunnel URL:', url)
client = Client()
client.incoming_phone_numbers.list(
phone_number=os.environ.get('TWILIO_PHONE_NUMBER'))[0].update(
sms_url=url + '/bot')
I can't explain all the things that I tried in the last 4 days, with no success. I keep getting the same error:
client.incoming_phone_numbers.list(phone_number=os.environ.get('TWILIO_PHONE_NUMBER'))[0].update(sms_url=url + '/bot')
IndexError: list index out of range
Something is not working with the list, it comes empty, although environment variables are working properly. I will work with just one phone_number, so there no need for list, indeed, so I started to change that line to avoid different errors and ended up with this:
def start_ngrok():
from twilio.rest import Client
from pyngrok import ngrok
url = ngrok.connect(5000)
print(' * Tunnel URL:', url)
client = Client()
client.incoming_phone_numbers("my_number").update(sms_url=str(url) + '/bot')
Then I got the final error that I can't solve by my self:
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/twilio/rest/api/v2010/account/incoming_phone_number/__init__.py", line 442, in update
payload = self._version.update(method='POST', uri=self._uri, data=data, )
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/twilio/base/version.py", line 106, in update
raise self.exception(method, uri, response, 'Unable to update record')
twilio.base.exceptions.TwilioRestException:
HTTP Error Your request was:
POST /Accounts/my_account_SID/IncomingPhoneNumbers/+my_number.json
Twilio returned the following information:
Unable to update record: The requested resource /2010-04-01/Accounts/my_account_SID/IncomingPhoneNumbers/+my_number.json was not found
More information may be available here:
https://www.twilio.com/docs/errors/20404
I tried all different phone numbers combinations/formats: nothing works.
Thanks for your time reading all this!
Looks like something changed since the blog was written or there was a mistake.
Try the below:
The only difference is adding .public_url to the url object. Also allowed a GET to /bot for testing.
from dotenv import load_dotenv
from flask import Flask, request
from twilio.twiml.messaging_response import MessagingResponse
load_dotenv()
app = Flask(__name__)
#app.route('/bot', methods=['POST','GET'])
def bot():
user = request.values.get('From', '')
resp = MessagingResponse()
resp.message(f'Hello, {user}, thank you for your message!')
return str(resp)
def start_ngrok():
from twilio.rest import Client
from pyngrok import ngrok
url = ngrok.connect(5000)
print('This is',url)
print(' * Tunnel URL:', url)
client = Client()
client.incoming_phone_numbers.list(
phone_number=os.environ.get('TWILIO_PHONE_NUMBER'))[0].update(
sms_url=url.public_url + '/bot')
if __name__ == '__main__':
if os.environ.get('WERKZEUG_RUN_MAIN') != 'true':
start_ngrok()
app.run(debug=True)

Is there a way to verify that an iOS Registration Token is valid or Invalid?

I already understand the proper procedure for obtaining a push registration token from APNS when the app launches so that that you always have a valid token. But for troubleshooting, is there an API for checking the validity of a registration token similar to how you can validate a push cert?
Here's the solution using the python script below.
Credit solution to Dara Kong
Send test APNS notifications to device using cert
usage:
push_debug.py [-h] [-s] certificate device_id
positional arguments:
certificate path to push certificate
device_id device ID
optional arguments:
-h, --help show this help message and exit
-s, --sandbox Use APNS sandbox environment
Send notification through production environment
python push_debug.py my_certificate.pem c35124fd2676d646423705b0721004e3b8426d163e10dbf76b46347a4477f12b
Send notification through sandbox environment
python push_debug.py -s my_certificate.pem 3f3980225497e1846fb5c2db9e0b3510023402c7a772011106c702d2aec20cc5
Save this script to file named push_debug.py
import json
import logging
import os
import socket
import ssl
import struct
import sys
import time
import uuid
import argparse
APNS_HOST = 'gateway.push.apple.com'
APNS_HOST_SANDBOX = 'gateway.sandbox.push.apple.com'
APNS_PORT = 2195
APNS_ERRORS = {
1:'Processing error',
2:'Missing device token',
3:'missing topic',
4:'missing payload',
5:'invalid token size',
6:'invalid topic size',
7:'invalid payload size',
8:'invalid token',
255:'Unknown'
}
def push(cert_path, device, sandbox):
if not os.path.exists(cert_path):
logging.error("Invalid certificate path: %s" % cert_path)
sys.exit(1)
device = device.decode('hex')
expiry = time.time() + 3600
try:
sock = ssl.wrap_socket(
socket.socket(socket.AF_INET, socket.SOCK_STREAM),
certfile=cert_path
)
host = APNS_HOST_SANDBOX if sandbox else APNS_HOST
sock.connect((host, APNS_PORT))
sock.settimeout(1)
except Exception as e:
logging.error("Failed to connect: %s" % e)
sys.exit(1)
logging.info("Connected to APNS\n")
for ident in range(1,4):
logging.info("Sending %d of 3 push notifications" % ident)
payload = json.dumps({
'aps': {
'alert': 'Push Test %d: %s' % (ident, str(uuid.uuid4())[:8])
}
})
items = [1, ident, expiry, 32, device, len(payload), payload]
try:
sent = sock.write(struct.pack('!BIIH32sH%ds'%len(payload), *items))
if sent:
logging.info("Message sent\n")
else:
logging.error("Unable to send message\n")
except socket.error as e:
logging.error("Socket write error: %s", e)
# If there was an error sending, we will get a response on socket
try:
response = sock.read(6)
command, status, failed_ident = struct.unpack('!BBI',response[:6])
logging.info("APNS Error: %s\n", APNS_ERRORS.get(status))
sys.exit(1)
except socket.timeout:
pass
except ssl.SSLError:
pass
sock.close()
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Send test APNS notifications to device using cert")
parser.add_argument("certificate", help="path to push certificate")
parser.add_argument("device_id", help="Device ID")
parser.add_argument("-s", "--sandbox", action="store_true", help="Use APNS sandbox environment")
args = parser.parse_args()
logging.basicConfig(level=logging.INFO)
push(args.certificate, args.device_id, args.sandbox)
logging.info("Complete\n")

How to telnet an address?

I'm trying to understand the socket class and i'm using the following example to implement a server sample
local server = assert(socket.bind("*", 0))
-- find out which port the OS chose for us
local ip, port = server:getsockname()
-- print a message informing what's up
print("Please telnet to localhost on IP [" ..ip.. "] and port [" .. port .. "]")
print("After connecting, you have 10s to enter a line to be echoed")
-- loop forever waiting for clients
while true do
-- wait for a connection from any client
local client = server:accept()
-- make sure we don't block waiting for this client's line
client:settimeout(10)
-- receive the line
local line, err = client:receive()
-- if there was no error, send it back to the client
if not err then
client:send(line .. "\n")
end
-- done with client, close the object
client:close()
end
But now the question is, how can I telnet for example the address localhost:8080 via lua?
EDIT:
I forgot to tell something, I donĀ“t even can telnet on cmd. When I type the command:
telnet ip port
it always says "connection lost" after I send a message. What am I doing wrong?
First, follow the instructions from here to enable telnet in Windows 7:
Go to Control Panel
Find Turn Windows features on or off under Programs (depending on layout)
Find Telnet client and enable it.
Once you've done that, it should work as expected.
Done!
local socket = require("socket")
local server = socket.connect(ip, port)
local ok, err = server:send("RETURN\n")
if (err ~= nil) then
print (err)
else
while true do
s, status, partial = server:receive(1024)
print(s or partial)
if (status == "closed") then
break
end
end
end
server:close()

Resources