I am using pyTelegramBotApi and I would like to get the id of the message sent to a chat and then forward it to other chats the problem is that i always get this exception 'AsyncTask' object has no attribute 'message_id' while the message is sent correctly
how to solve?
bot = telebot.AsyncTeleBot(bot_token)
res = bot.send_message(cid,message)
try:
message_id = res.message_id
print(message_id)
except Exception as e:
print(e)
Since send_message() is an AsyncTask, you'll need to .wait() until the event is done;
res = bot.send_message(cid,message)
try:
result = res.wait()
print(result.message_id)
except Exception as e:
print(e)
More telegram-bot docs.
Related
I create an email with the following.
def createGmailEmailNoAttachments(self, messageBody, subject, toEmail, fromEmail, html=False):
try:
newMessage = MIMEMultipart()
newMessage['to']=toEmail
newMessage['from'] = fromEmail
newMessage['subject'] = subject
if html:
msg= MIMEText(messageBody, 'html')
else:
msg= MIMEText(messageBody)
newMessage.attach(msg)
raw = base64.urlsafe_b64encode(newMessage.as_bytes())
raw = raw.decode()
body = {'raw': raw}
return body
except:
self.GLogger.error("An error was encountered while attempting to create gmail email")
tb = traceback.format_exc()
self.GLogger.exception(tb)
return False
I send an email with the following.
def gmailAPISendEmail(self, message, userID="me"):
try:
service = self.gmailAPIService
self.GLogger.info("Attempting to send email message")
request = service.users().messages().send(userId=userID, body=message)
response = self.executeGmailAPI_withretry(request)
if response is False:
return False
responseID = str(response['id'])
self.GLogger.info("Successfully sent email message with ID (" + responseID +")")
return responseID
except:
self.GLogger.error("Failed to send email message")
tb = traceback.format_exc()
self.GLogger.exception(tb)
return False
Where I execute the request in the function executeGmailAPI_withretry(request)
def executeGmailAPI_withretry(self, request, withHTTPObject = False):
try:
response_valid = False
num_retries = 0
while num_retries < 30:
try:
if withHTTPObject is True:
response = request.execute(http=self.http_toUse)
else:
response = request.execute()
response_valid = True
break
except socket.timeout:
num_retries = num_retries + 1
time.sleep(0.5*num_retries)
except:
self.GLogger.error("An error was encounrtered in executeGmailAPI_withretry")
try:
self.GLogger.error(f"The Method ID : {request.methodId}")
except:
pass
try:
self.GLogger.error(f"The uri : {request.uri}")
except:
pass
tb = traceback.format_exc()
self.GLogger.exception(tb)
num_retries = num_retries + 1
time.sleep(0.5*num_retries)
if response_valid is False:
self.GLogger.error(f"Could not resolve issue in 15 requests [{request}]")
return False
else:
return response
except:
self.GLogger.error("An error was encounrtered in executeGmailAPI_withretry")
tb = traceback.format_exc()
self.GLogger.exception(tb)
return False
The problem that I am encountering is as follows. Sometimes, when I want to send an email with these three functions, socket.timeout errors occur during execution of service.users().messages().send(userId=userID, body=message). My retry function will try to send it up to 30 times with some time delays in between. However, sometimes, when a socket.timeout error occurs, the email is still sent. This can result in several of the same emails being sent. From the code's perspective, only one email was sent, since service.users().messages().send(userId=userID, body=message) ran only once successfully without throwing an error.
So, for example, I had 4 identical emails being received, meaning that at least 3 send attempts had a socket.timeout errors in which Gmail actually did send the email and the 4th (or more) attempt executed without throwing the socket.timeout error.
Why does the Gmail API throw a socket.timeout error while sending an email, but still continue to send the email?
This creates a dilemma in the current situation.
If I handle the errors, then it ensures that emails that truly cannot be sent on the first try will be sent. However, it can result in multiple identical emails being sent, due to the false errors.
If I don't handle the error, then for certain, only one email at most will be sent. However, if the email truly cannot be sent, then it will certainly not be sent.
The ideal solution is that the Gmail API should only throw an error if the email truly cannot be sent.
You might want to try setting longer timeout for it to be in timeout mode. See socket.setdefaulttimeout(timeout).
This will force the script to wait until the specified timeout before raising a timeout exception. This way, you might be able to prevent premature timeout exceptions.
If it still doesn't work, maybe you could file it as a bug on issue tracker.
Reference:
socket.timeout with will cause api client to become unuseable
Socket Timeouts
Im sending messages to a topic in pubsub with this script:
publisher = pubsub_v1.PublisherClient()
topic_path = publisher.topic_path("my-project", "my-topic")
while True:
msg = b"some message"
future = publisher.publish(topic_path, msg)
try:
result = future.result()
except Exception as ex:
# handle exception
print(ex)
time.sleep(3)
My problem is how to make my print(ex) to print when a message is not posted on pubsub or detect when message wasn't sent and try to post it again.
You can check this article as it implemented error handling for publishing. A method was created for getting callbacks. It accepts future object and data string. If there is an exception, it will call exception() to return the raised exception.
def get_callback(f, data):
def callback(f):
try:
print(f.result())
futures.pop(data)
except: # noqa
print("Please handle {} for {}.".format(f.exception(), data))
return callback
This method was used to implement get_callback by passing the "future" and "data" parameters. Wherein future is a object and data is string.
for i in range(10):
data = str(i)
futures.update({data: None})
# When you publish a message, the client returns a future.
future = publisher.publish(topic_path, data.encode("utf-8"))
futures[data] = future
# Publish failures shall be handled in the callback function.
future.add_done_callback(get_callback(future, data))
# Wait for all the publish futures to resolve before exiting.
while futures:
time.sleep(5)
I am trying to create a Telegram bot that allows users to search up recipes that require only ingredients that they have on-hand. It is built with Python and I have a rough code, but before I fine-tune the details, I want to get the basic form of it up and running. Unfortunately, I am facing difficulty in parsing the API for the recipes corresponding to ingredients that the user has listed in his/her message. Specifically, the logged error message is "Error parsing the API". Could someone take a look at my code and help me see what went wrong please?
This is the relevant portion of my code:
def handle_messages(messages):
for message in messages:
mappedIngreds = []
for i in range(len(message.text)):
ingred = message.text[i].lower()
if i == 0:
mappedIngreds.append(ingred)
else:
mappedIngreds.append(f"+ {ingred}")
# get responses from API
try:
response = requests.get(f"{apiURL}{mappedIngreds}{apiId}{apiKey}")
response.raise_for_status() # for debugging
except requests.RequestException:
logging.error("Error connecting to the API")
return None
# format responses into list of recipes
try:
recipes = []
for i in response.json():
recipeInfo = {}
recipeInfo["name"] = i["label"]
recipeInfo["url"] = i["url"]
recipes.append(recipeInfo)
except (KeyError, TypeError, ValueError):
logging.error("Error parsing the API")
return None
# send list of recipes to user
try:
bot.reply_to(message.chat.id, "Try these recipes:", *recipeInfo["name"], *recipeInfo["url"], sep="\n")
except:
logging.error("Error printing recipes")
My full code is here: https://pastebin.com/W0CceAt9
I am using the following approach for handling Twilio exceptions in Python:
try:
#code for sending the sms
print(message.sid)
except TwilioRestException as e:
print(e)
This allows me to send sms and Exceptions are handled by Python.
Now I need to "return" the exceptions codes in order to process them, let's say, give user a message depending on the exception.
How can I achieve that?
If raising exception is not an option you could simply add return under except block.
def func():
# your logic
try:
#code for sending the sms
print(message.sid)
except TwilioRestException as e:
print(e)
return e.code # or whetever attribute e has for it...
By default function will return None if everything goes right. In client code it will be like
err = func()
if err:
# sms wasn't sent, action required
I own a shared hosting which can run anacrontab. I would like to run a python script when I receive an email on that server.
Is anacrontab enough?
Or would using a client such as Gmail be better?
import imapclient, pyzmail, html2text
def latestMail():
imapObj = imapclient.IMAPClient('imap.yourServer.com', ssl=False)
imapObj.login('imapUser', 'imapPass')
imapObj.select_folder('Inbox', readonly=False)
UIDs = imapObj.search(criteria='ALL', charset=None)
rawMessages = imapObj.fetch(UIDs[0], ['BODY[]', 'FLAGS'])
message = pyzmail.PyzMessage.factory(rawMessages[UIDs[0]]['BODY[]'])
return message
def parser(message):
if message.text_part is not None and message.html_part is not None:
multipart = True
else:
multipart = False
if message.text_part is not None:
try:
body = message.text_part.get_payload().decode(message.text_part.charset)
except TypeError:
body = message.text_part.get_payload()
if message.html_part is not None and multipart is False:
try:
body = html2text.html2text(message.html_part.get_payload().decode(message.html_part.charset))
except Exception:
raise Systemexit
return body
try:
message = latestMail()
clean = parser(message)
print clean
except IndexError:
print "No messages left"
raise os._exit(0)
except Exception as e:
print e
Crontab config:
HOME=/var/www/html/whatever
* * * * * root /var/www/html/whatever/myMailChecker.py
Conclusion:
This will call your imap servers' Inbox every minute and parse trough your mail and parse it's content, you can do whatever you want after like create a new entry in your mysql table with the mail content etc.. or run another script if clean is not None etc.