Gmail API - How to relabel emails as spam using Filters? - gmail

I am attempting to write a bot which searches for an email by a keyword, then creates a filter sending all future emails from that sender to spam.
Here is my code:
async def remove_subscription(service, from_email, message):
# labels = service.users().labels().list(userId='me').execute().get('labels', [])
# for label in labels:
# print(label['id'])
filter_content = {
'criteria': {
'from': from_email
},
'action': {
'addLabelIds': ['SPAM'],
'removeLabelIds': ['INBOX']
}
}
try:
result = service.users().settings().filters().create(
userId='me', body=filter_content).execute()
print(F'Created filter with id: {result.get("id")}')
return True
except:
print('An error occurred')
await message.channel.send('An error occurred.')
return False
As you can see, it is pretty much the given code from the google docs:
https://developers.google.com/gmail/api/guides/filter_settings?hl=en
The api won't allow me to use addLabelIds: ['SPAM'], and it does not work while attempting to do the same query on the gmail docs in-webpage testing (So I know it isnt an issue with the rest of my code). Here is the error:
raise HttpError(resp, content, uri=self.uri)
googleapiclient.errors.HttpError: <HttpError 400 when requesting https://gmail.googleapis.com/gmail/v1/users/me/settings/filters?alt=json returned "Invalid label SPAM in AddLabelIds". Details: "[{'message': 'Invalid label SPAM in AddLabelIds', 'domain': 'global', 'reason': 'invalidArgument'}]">
I can't seem to find an explanation anywhere which states that I can't add SPAM as a label ID. I confirmed with lines 2-4 that the label ID is indeed 'SPAM".
Is this just not allowed by the api? How could I create a filter which sends all emails from a specific sender to spam?
Thanks ahead of time.

Issue:
I don't think Gmail allows messages to be sent to SPAM via filters. This is true not just for the API, but for the user-interface too:
If you'd like this feature to be added to Gmail, I'd suggest requesting it via Send feedback on the user-interface. Nevertheless, it's likely that this is a deliberate limitation. In any case, you could use a custom label to act as SPAM.
Related:
How to send messages to spam in Gmail filter?

Related

What's the right way to execute a Twilio Studio conversation flow?

Im learning how to set a twilio studio flow with python, I'm currently testing one of the templates that Twilio provides, and Im communicating with the bot from WhatsApp. However, I can only send the first message of the flow and if I send another message, this message pop up:
Unable to create record: Execution XXXXXXXXXXXXXXXXXXXXX is already active for this contact. End the active Execution before creating a new one
I tried to add .update(status='ended') to my variable, but it just kinda looped every time I sent a message, I know that every time that theres an incoming message it will trigger the conversation. So my question is, how can I continue the conversation flow without creating a new trigger every time that theres an incomming message?
Here's my flow in case it's necessary.
And this is the functions and endpoints that I'm using to trigger the action:
# twilio.route('/incoming_message', methods=['GET', 'POST'])
def incoming_message_data() -> str:
if request.method == 'POST':
response = {}
error, message, code = False, '', ''
message = incoming_message()
response.update({'sucess': True, 'message': message, 'message': f'{message}', 'status_code': 200, 'error': None, 'code': f'{code}'} if message and message != [{}]else {
'sucess': False, 'message': 'Message could not be sent', 'status_code': 400, 'error': f'{error}', 'code': f'{code}'})
return message
def twilio_studio_flow(phone_number: str) -> str:
'''
Twilio Studio Flow
'''
response = request.values.get('Body', '').lower()
execution = twilio_client.studio \
.v2 \
.flows(Config.TWILIO_STUDIO_FLOW_SID) \
.executions \
.create(to=(f'whatsapp:{phone_number}'), from_=Config.TWILIO_PHONE_NUMBER,
parameters={
"appointment_time": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
})\
.update(status='ended')
def validate_phone_number(phone_number: str) -> bool:
'''
Validate phone number
'''
try:
phone = phonenumbers.parse(phone_number.strip(), None)
client = Client.query.filter_by(phone=phone_number).first()
return phonenumbers.is_valid_number(phone) and client is not None
except Exception:
return False
def incoming_message() -> str:
'''
Receive incoming messages
'''
# Get the message the user sent our Twilio number
incoming_message = request.values.get('Body', '').lower()
# Get the phone number of the person sending the text message
phone_number = request.values.get('From', None).replace('whatsapp:', '')
resp = MessagingResponse()
if validate_phone_number(phone_number) and incoming_message:
resp.message(twilio_studio_flow(phone_number))
else:
resp.message(
'Lo sentimos, no pudimos validar tu numero de telefono 😟')
return str(resp)
Thanks in advance for helping me :).
As I mentioned previously, I want to know the right way to execute a Twilio Studio. Honestly, I cheked the docs but it's a little bit unclear on how to this.
Based on your answer in the comments, I'd suggest to link the Studio flow directly to the WhatsApp sender in the console (instead of invoking the flow manually via the API).
To connect the Studio Flow to your WhatsApp number ("Sender"). Click on the Trigger (Start) Widget and locate the Webhook URL field in the right-hand menu. Copy that URL to your clipboard.
Next, navigate to your WhatsApp Senders in the Twilio console. Click to select the sender that you want to use with this Studio Flow. Paste the Webhook URL that you copied from your Studio Flow into the field Webhook URL for incoming messages. Don't forget to click Update WhatsApp Sender.
Now, any time you receive an inbound message on your selected WhatsApp-enabled sender (number), it will be routed to your new Studio Flow.
Taken from the documentation.

send message from bot to direct message after typing /slash command

I'm trying to make SlackBot and if I call him in some public channel it works fine but when I call him (type slash-command) in any direct channel I receive "The server responded with: {'ok': False, 'error': 'channel_not_found'}". In public channels where I've invited my bot it works fine, but if I type "/my-command" in any DM-channel I receive response in separate DM-channel with my bot. I expect to receive these responses in that DM-channel where I type the command.
Here is some part of my code:
if slack_command("/command"):
self.open_quick_actions_message(user_id, channel_id)
return Response(status=status.HTTP_200_OK)
def open_quick_actions_message(self, user, channel):
"""
Opens message with quick actions.
"""
slack_template = ActionsMessage()
message = slack_template.get_quick_actions_payload(user=user)
client.chat_postEphemeral(channel=channel, user=user, **message)
Here are my Event Eubscriptions
Here are my Bot Token Scopes
Can anybody help me to solve this?
I've already solved my problem. Maybe it will help someone in the future. I've sent my payload as the immediate response as it was shown in the docs and the response_type by default is set to ephemeral.
The part of my code looks like this now:
if slack_command("/command"):
res = self.slack_template.get_quick_actions_payload(user_id)
return Response(data=res, status=status.HTTP_200_OK)
else:
res = {"text": "Sorry, slash command didn't match. Please try again."}
return Response(data=res, status=status.HTTP_200_OK)
Also I have an action-button and there I need to receive some response too. For this I used the response_url, here are the docs, and the requests library.
Part of this code is here:
if action.get("action_id", None) == "personal_settings_action":
self.open_personal_settings_message(response_url)
def open_personal_settings_message(self, response_url):
"""
Opens message with personal settings.
"""
message = self.slack_template.get_personal_settings_payload()
response = requests.post(f"{response_url}", data=json.dumps(message))
try:
response.raise_for_status()
except Exception as e:
log.error(f"personal settings message error: {e}")
P. S. It was my first question and first answer on StackOverflow, so don't judge me harshly.

Discord.py - Cannot try/except 403: User does not accept DMs

I've been looking everywhere for this, but the try/except never worked for me and got me multiple errors. The code is to ban every member from server and send a DM that the server was deleted. It works, but the bot stops at a person with the error "Cannot send messages to this user" and I'd like to handle it, but always got errors like: indent expected or expression expected. The code I have without try/catch is:
#client.command(pass_context=True)
async def abandon(ctx):
for member in ctx.guild.members:
if len(member.roles) < 2:
await member.send(f"Hello {member.display_name},\n\n" + banreason + banreason2 + banreason3)
await member.ban(reason="Executed due to deletion of the server. Invite links were sent in DMs.")
await ctx.send(f"**{member.display_name}** was banned and invite links were sent. :white_check_mark:")
print(f"Banned {member.display_name} and invite links were sent.")
print("Banning complete!")
How can I import a correct try/catch bracket around await member.send?
EDIT: Added code with the exception handling:
#client.command(pass_context=True)
async def abandon(ctx):
for member in ctx.guild.members:
if len(member.roles) < 2:
try:
print(f"Debug: Targeted user is {member.display_name}")
except CommandInvokeError:
ctx.send(f"{member.display_name}" + resolvedmerror)
print(f"{member.display_name} was banned with 403 Forbidden exception (No DMs accepted by user)")
pass
await member.send(f"Hello {member.display_name},\n\n" + banreason + banreason2 + banreason3)
await member.ban(reason="Executed due to deletion of the server. Invite links were sent in DMs.")
await ctx.send(f"**{member.display_name}** was banned and invite links were sent. :white_check_mark:")
print(f"Banned {member.display_name} and invite links were sent.")
print("Banning complete!")
I just had the simple format problem by using space instead of tab. Haha python is oversensitive and I thought something is needed, but was only one press.

Difference in the receive and send method in a websocket

I am looking over the following code which does a 'group chat' with different members:
# Receive message from WebSocket
def receive(self, text_data):
text_data_json = json.loads(text_data)
message = text_data_json['message']
# Send message to room group
async_to_sync(self.channel_layer.group_send)(
self.room_group_name,
{
'type': 'chat_message',
'message': 'OK'
}
)
# Receive message from room group
def chat_message(self, event):
message = event['message']
# Send message to WebSocket
self.send(text_data=json.dumps({
'message': message
}))
My questions is what do the two items do? I see that receive(), also does the group_send, so what purpose does the chat_message have if the receive sends it upon receiving it?
That chat server code is a simple example on how to send group messages.
In the code:
async_to_sync(self.channel_layer.group_send)(
self.room_group_name,
{
'type': 'chat_message',
'message': 'OK'
}
)
this line
'type': 'chat_message',
is responsible for calling method chat_message() with { 'message': 'OK'}
Before sending this message to the group members you may want to modify or check the data, or need to do other stuff. That's why self.channel_layer.group_send doesn't directly sends message to the group but calls another method (in this case chat_message) to handle sending of message and to keep receive() method's code clean.

Messenger Send API

I am creating a self built Python chatbot that does not use a chatbot platform such as Dialogflow. The issue is that there is no easy integration with messaging apps such as Messenger to connect it too. I am trying to create a webhook to Messenger using the Messenger Send API. I am looking at the documentation and it shows me how to request a POST api call. However when I look at examples online they all seem to deal with json values called "entry" and "messaging" which I can't find anywhere and can't seem to see why it is necessary. I was wondering how exactly the input body of a Messenger Send API looks like so I can call it appropriately and what json objects are in its body. This is what I have so far from following online examples. I am using Flask. And am using Postman to test this
#app.route("/webhook", methods=['GET','POST'])
def listen():
if request.method == 'GET':
return verify_webhook(request)
if request.method == 'POST':
payload = request.json
event = payload['entry'][0]['messaging']
for x in event:
if is_user_message(x):
text = x['message']['text']
sender_id = x['sender']['id']
respond(sender_id, text)
return "ok"
Below is what I think the body of the request looks like:
{
"object":"page",
"entry":[
{
"id":"1234",
"time":1458692752478,
"messaging":[
{
"message":{
"text":"book me a cab"
},
"sender":{
"id":"1234"
}
}
]
}
]
}
But it is unable to read this and gives me an error of:
File"/Users/raphael******/Documents/*****_Project_Raphael/FacebookWebHookEdition.py", line 42, in listen
event = payload['entry'][0]['messaging']
TypeError: 'NoneType' object is not subscriptable
Where am I going wrong that the webhook is not registering the body correctly as json objects?
Here is how we do it:
# GET: validate facebook token
if request.method == 'GET':
valid = messenger.verify_request(request)
if not valid:
abort(400, 'Invalid Facebook Verify Token')
return valid
# POST: process message
output = request.get_json()
if 'entry' not in output:
return 'OK'
for entry in output['entry']:
if 'messaging' not in entry:
continue
for item in entry['messaging']:
# delivery notification (skip)
if 'delivery' in item:
continue
# get user
user = item['sender'] if 'sender' in item else None
if not user:
continue
else:
user_id = user['id']
# handle event
messenger.handle(user_id, item)
# message processed
return 'OK'
EDIT:
If you are using postman, please make sure to also set Content-Type header to application/json, otherwise Flask can't decode it with request.json. I guess that's where None comes from in your case.

Resources