Slack API: channel_not_found error when using chat.postMessage - python-3.x

I have written the code to post to a channel within the workspace on slack for any given channel (assuming it exists), but I keep getting the channel_not_found error on channels that
1.) I can verify that they do indeed exist
2.) The channels are not private as they have the # symbol in front of them and not a lock.
I have triple checked my slack app dashboard and it is installed on the workspace (verified with workspace admins also). I have stored both the OAuth Access Token (begins with xoxp) and the Bot User OAuth Access Token (begins with xoxb) as an environment variable on my machine. I have tried using both within the app and I get the same result with the following permissions/scopes: chat:write:bot, chat:write:user, and bot. I can send messages via webhooks, but am understanding that I need to create a webhook for each and every channel that the app may be posting to. This app needs to be versatile and able to direct message users depending on how they wish to be updated. Any help in finding why the channels cannot be found would greatly be appreciated. In the following code snippet, the post_channel() function is the test function that I am using and simple changing out channel names, etc.
from slackclient import SlackClient
import os
webhook_url = "a webhook url"
def post_message_channel(text, token, channel, is_name):
"""
Creates an api call to post to a message to specific channel (private or
public)and returns the JSON object that is returned by the slack api call.
:param text: The message to post the slack channel.
:param token: The slack app token to identify the sender.
:param title: The title of the message being sent.
:param channel: The channel to post the message to.
:param is_name: If true, then the channel param holds a name, else it holds a channel id
:return: The JSON object that the slack api responds with.
"""
if is_name:
formatted_channel = "#" + channel
else:
formatted_channel = channel
slack_client = SlackClient(token)
output_json = slack_client.api_call(
"chat.postMessage",
channels = formatted_channel,
text = text,
as_user = 1
)
return output_json
def post_channel():
message = "This is a test for posting to a channel"
my_token = os.environ["SLACK_BOT_USER_TOKEN"]
print(post_message_channel(message, my_token, 'file_tracker_test', True))

Related

How to determine which user clicked on a button

I'm sending messages with block elements (buttons) to channel using Slack API. How can I get the username displayed when someone approves or rejects the request? I send the message using chat.postMessage.
You should have interactivity enabled for your app. Since you are using buttons you need to reference how to handle interactive components. Essentially, you need to give your buttons an action_id which is it's unique identifier and will help you determine the source of the action (including the user) when the button is clicked. You will parse the action payload that sent to your app to get the user information you need and use that information in a subsequent call to chat.postMessage.
I was having trouble getting the user with the payload, using body instead worked for me:
In Bolt Python:
#app.action("approve_button")
def approve_request(ack, say, body, payload):
# Acknowledge action request
ack()
user_details = body['user']
username = user_details['name']
.....

Proactive messaging bot in Teams without mentioning the bot beforehand

I'm using the Microsoft bot-framework to create a bot and integrate it into teams.
Part of the bot's requirements include proactively messaging users once per day. From what I understand, I can only message users that has been added to the team/groupChat after the bot, or that have messaged the bot directly.
My question is - can I somehow bypass this limitation?
A friend of my referred me to a new feature of graphAPI, as part of the new beta version - https://learn.microsoft.com/en-us/graph/api/user-add-teamsappinstallation?view=graph-rest-beta&tabs=http.
To me it doesn't seem like it could be related to the solution since I'm not getting any data back in the response, so if I have no conversationReference object I still can't message the user.
At the moment my solution is to simply broadcast a message in the channel when it's added, asking users to "register" with it by messaging it. Anyone has any other suggestion?
The easiest way is to:
Install the bot for the team
Query the Team Roster -- The link in Step 3 has an alternative way to do this towards the bottom
Create a conversation with the user and send a proactive message
There's a lot of code in those links and it's better to just visit them than to copy/paste it here.
The end of Step 3 also mentions trustServiceUrl, which you may find handy if you run into permissions/auth issues when trying to send a proactive message.
Edit for Node:
Install Necessary Packages
npm i -S npm install botbuilder-teams#4.0.0-beta1 botframework-connector
Note: The #<version> is important!
Prepare the Adapter
In index.js
const teams = require('botbuilder-teams');
adapter.use(new teams.TeamsMiddleware());
Get the Roster
// Get Team Roster
const credentials = new MicrosoftAppCredentials(process.env.MicrosoftAppId, process.env.MicrosoftAppPassword);
const connector = new ConnectorClient(credentials, { baseUri: context.activity.serviceUrl });
const roster = await connector.conversations.getConversationMembers(context.activity.conversation.id);
Send the Proactive Message
const { TeamsContext } = require('botbuilder-teams');
// Send Proactive Message
const teamsCtx = TeamsContext.from(context);
const parameters = {
members: [
roster[0] // Replace with appropriate user
],
channelData: {
tenant: {
id: teamsCtx.tenant.id
}
}
};
const conversationResource = await connector.conversations.createConversation(parameters);
const message = MessageFactory.text('This is a proactive message');
await connector.conversations.sendToConversation(conversationResource.id, message);
Trust the ServiceUrl, as Necessary
Read about it. You'd want this before the message is sent.
MicrosoftAppCredentials.trustServiceUrl(context.activity.serviceUrl);
EDIT: The Graph API you've referenced is only necessary if you wish to proactively message a user who is not in a channel/groupChat where the bot is installed. If you need to proactively message only people who are in context where the bot is installed already, the answer from mdrichardson is the easiest possible method.
We've identified a couple of issues with the Graph API beta endpoint you referenced that should be fixed in the near term. In the meantime workarounds are as follows:
Calling:
POST https://graph.microsoft.com/beta/me/teamwork/installedApps/
{"teamsapp#odata.bind":"https://graph.microsoft.com/beta/appcatalogs/teamsapps/APP-GUID"}
Will install an app in the personal scope of a user.
Known issue: Currently, if the app contains a bot, then installation will not lead to creation of thread between the bot and the user. However to ensure that any missing chat threads, get created, call:
GET https://graph.microsoft.com/beta/me/chats?$filter=installedApps/any(x:x/teamsApp/id eq 'APP-GUID')
Calling:
GET https://graph.microsoft.com/beta/me/chats?$filter=installedApps/any(x:x/teamsApp/id eq 'APP-GUID')
Gets the chat between a user and an app containing a bot.
Known issue: Calling this API will lead to sending a conversation update event to the bot even though there were no updates to the conversation. Your bot will essentially get two install events and you'll need to make sure you don't send the welcome message twice.
We'll also be adding more detailed documentation for the proactive messaging flow using these Graph APIs

Send emails through gmail using flask-mail

I have a simple CRUD webapp set up in Python/Flask, when one particular function is activated (approving a request) I'd like to send an email notification to the user, but for all I've tried I can't get the email to send through my code.
Here is my config file with all the relevant environment variables set (inside of a Config object):
MAIL_SERVER = 'smtp.gmail.com'
MAIL_PORT=465
MAIL_USE_SSL=True
MAIL_USERNAME = '**#gmail.com'
MAIL_PASSWORD = '**'
I have also tried calling app.config.update(those values) in my app/init.py file. Here is the current code to do so
mail = Mail()
def create_app(config_name):
app = Flask(__name__, instance_relative_config=True)
app.config.from_object(app_config[config_name])
app.config.from_pyfile('./config.py')
app.config.update(
MAIL_SERVER='smtp.gmail.com',
MAIL_PORT=465,
MAIL_USE_SSL=True,
MAIL_USE_TLS=False,
MAIL_USERNAME = '**#gmail.com',
MAIL_PASSWORD = '**')
mail.init_app(app)
And finally here is the code where I actually attempt to send the email:
msg = Message(html=html, sender='**#gmail.com', subject='Your Reservation for %s' % reservation.item.name, recipients=['**'])
mail.send(msg)
Additionally, it currently fails silently and I don't know how to even view what error is happening. Any help is much appreciated!
My suggestion in the comments was indeed the answer to the question.
Enabling "Less Secure Apps" in the Google Account settings was the necessary step to fix the hangup the OP was experiencing. This link from Google's support page walks you through how to enable this option.
I think, you should switch your sending protocol to TLS
this is sample from my project
MAIL_SERVER='smtp.gmail.com',
MAIL_PORT=587,
MAIL_USE_TLS=True,
MAIL_USERNAME = '**#gmail.com',
MAIL_PASSWORD = '**'
for me this works very well.
Now that Google is removing the less-secure app access feature due to security reasons, the best way to get around this is to use Sendgrid. They provide 100 free emails per day forever. You can register your same Gmail address as a single sender in SendGrid. Generate an API key and use it in your flask app to send emails.
For reference: Sending Emails from Python Flask Applications With Twilio SendGrid

How to update message status with the Slack WEB API

Is there a way to update the status of a message sent from the Slack Web API?
I'm using Slack to build a bot that send Slack messages as SMS using Twilio and I would like to notice the user that the message hasn't been sent if the Twilio call response is an error.
Any suggestions?
I can suggest a blog post by one of my colleagues that walks you through building an SMS Slack bot in Python. You can use it as a guide to translate the setup to Node.js.
The tutorial there shows you how to both send SMS messages to Slack and receive Slack messages via SMS.
Specifically, the following route for receiving Slack messages as SMS:
#app.route('/slack', methods=['POST'])
def slack_post():
if request.form['token'] == SLACK_WEBHOOK_SECRET:
channel = request.form['channel_name']
username = request.form['user_name']
text = request.form['text']
response_message = username " in " channel " says: " text
twilio_client.messages.create(to=USER_NUMBER, from_=TWILIO_NUMBER,
body=response_message)
return Response(), 200
In addition to the code above you could handle any Twilio errors received on a message Status ErrorCode ErrorMessage and notify a user in Slack via the chat.update method.

How to build a slack bot to have multiple conversations?

I am building a slack bot using a third party service to handle responses based on inputs rather than just hard coding them into the bot. This service's API needs a client id & a conversation id to get the response. I found out that each time a slack bot receives a message, it creates a new message object each time so there isn't a way of keeping the clientID and conversation ID within the message object and have slack hold onto it.
rtm.on(RTM_EVENTS.MESSAGE, function(message // <-- new object each time the bot hears a message){
rtm.sendMessage('hello', message.channel);
});
So shortened down, does anyone know of a way to keep a conversation between a single user and the bot while holding onto some type of variable to hold the client and conversation ID?
You can store the message.user ID and track the conversation referring to that specific user. You will need to keep track of all ongoing conversations yourself. Something like this
rtm.on(RTM_EVENTS.MESSAGE, function(message // <-- new object each time the bot hears a message){
if(stored_conversations.indexOf(message.user) > -1){
//customize message depending on history
rtm.sendMessage('I remember you', message.channel);
}
});
Or, you could use Botkit - it manages bot-user conversations for you.

Resources