How in group chat
hide message to bot -- #mybot xxx?
send message from bot only to one user of group?
None of the channels that support bots being members of a group allow users to explicitly block a bot from getting messages, though some require that the bot is #mentioned in order to get any message sent in a group.
For those that support Direct Messages, the Bot can send a message to a single user as follows:
var response = await activityContext.ConnectorAPI.Conversations.CreateDirectConversationAsync(activity.Recipient, activity.From);
var reply = activity.CreateReply($"This is a direct message to {activity.From.Name ?? activity.From.Id} : {activity.Text}");
reply.Conversation = new ConversationAccount(id: response.Id);
reply.ReplyToId = null;
await activityContext.ConnectorAPI.Conversations.SendToConversationAsync(reply);
Related
I'm having an Adaptive card with a share button, on click of that button I have shared that card to other Teams channel, as of now I'm able to send the message to the same Teams channel, but while sending to other teams channel it giving me Error.
Below is the code i'm using:
var tenantID = activity.GetTenantId();
var message = Activity.CreateMessageActivity();
message.Text = "Hello World";
var conversationParameters = new ConversationParameters
{
IsGroup = true,
ChannelData = new TeamsChannelData
{
Channel = new ChannelInfo("ID of Channel to which message is to be sent"),
Team = new TeamInfo("ID of team to which message to be sent", "Name of team");
Tenant = new TenantInfo(tenantID),
Notification = new NotificationInfo(true)
},
Activity = (Activity)message
};
MicrosoftAppCredentials.TrustServiceUrl(activity.ServiceUrl, DateTime.MaxValue);
var connectorClient = new ConnectorClient(new Uri(activity.ServiceUrl));
await connectorClient.Conversations.CreateConversationAsync(conversationParameters);
MS Teams is quite picky (for a reason) when it comes to bot-id etc. You need to make sure that you have the same bot id configured in code and in your manifest.
On top of that, when you get the "Unable to reach the app" message, that most likely means your bot messaging endpoint (configured in the bot options on azure or on dev.botframework.com ) does not point to the correct url.
In general you can not send a message to a user who never interacted with your bot before in a 1:1 conversation and you can not send a message to any teams your bot is not added to as a member.
I've got a Bot Framework V3 bot code base that is working in a half dozen or so different customer Teams tenants, and on our internal Teams tenant without issues.
In one particular customer tenant, attempts to create a proactive message to a Teams Channel are failing with a ConversationNotFound 404 error, when I call ConnectorClient.Conversations.CreateConversationAsync().
My code to create the conversation and post an activity in the channel looks like this:
var teamsChannelId = "19:deadbeef1234#thread.skype"; // insert the real channel ID obtained from lookups against Graph API...
var botCredentials = new MicrosoftAppCredentials(/* Bot ID & password */);
MicrosoftAppCredentials.TrustServiceUrl("https://smba.trafficmanager.net/amer/", DateTime.MaxValue);
using (var connectorClient = new ConnectorClient(new Uri("https://smba.trafficmanager.net/amer/"), botCredentials)) {
var botId = new ChannelAccount("28:" + botCredentials.MicrosoftAppId);
var msg = Activity.CreateMessageActivity();
msg.From = botId;
var card = MakeCard(); // builds an AdaptiveCard...
msg.Attachments.Add(new Attachment(AdaptiveCard.ContentType, content: card));
var parameters = new ConversationParameters() {
Bot = botId,
ChannelData = new TeamsChannelData() {
Channel = new ChannelInfo(teamsChannelId)
},
Activity = (Activity)msg
};
// This throws an Microsoft.Bot.Connector.ErrorResponseException with the code "ConversationNotFound"
ConversationResourceResponse convoResponse = await connectorClient .Conversations.CreateConversationAsync(parameters);
}
As I mentioned initially, this code may not be perfect, but it is working on a number of different Teams and Azure environments, but failing in this particular environment. The HTTP response from Bot Framework looks like this:
"Response": {
"StatusCode": 404,
"ReasonPhrase": "Not Found",
"Content": "{\"error\":{\"code\":\"ConversationNotFound\",\"message\":\"Conversation not found.\"}}",
"Headers": {
"Date": [
"Wed, 04 Sep 2019 14:43:24 GMT"
],
"Server": [
"Microsoft-HTTPAPI/2.0"
],
"Content-Length": [
"77"
],
"Content-Type": [
"application/json; charset=utf-8"
]
}
Stack Trace:
Microsoft.Bot.Connector.ErrorResponseException: Operation returned an invalid status code 'NotFound'
at Microsoft.Bot.Connector.Conversations.<CreateConversationWithHttpMessagesAsync>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Bot.Connector.ConversationsExtensions.<CreateConversationAsync>d__3.MoveNext()
The bot is able to handle incoming 1-1 chat conversations without issue over webchat, directline and the Teams connectors, so I don't think there are any issues with the bot credentials, or the bot registration configuration.
The bot has been added as an app for Microsoft Teams, uploaded to the tenant, and added to the appropriate Team.
I've explored the possibility that the region of the Bot Framework registration in Azure might be causing an issue, but I've reproduced the client's configuration on our end, and can't reproduce the problem.
Any suggestions would be very welcome.
I have a feeling your parameters is missing the Tenant. This may explain why it fails on some tenants and not others. Try something like this:
var parameters = new ConversationParameters
{
Members = new[] { new ChannelAccount(userId) },
ChannelData = new TeamsChannelData
{
Tenant = new TenantInfo(activity.Conversation.TenantId),
},
};
#Trinetra-MSFT is also correct. You should not hard-code the service URL; some of your users may be outside /amer.
Although possible to some extent, "Proactive Messaging" shouldn't be thought of as "messaging users who have not spoken with the bot", so much as "messaging a user about something not related to a previous conversation". Generally speaking, proactive messaging needs to be done by saving a conversation reference from a user that the bot has had a past conversation with. This is how the Bot Framework, specifically, defines Proactive Messaging.
For Teams, per Proactive Messaging for Bots:
Bots can create new conversations with an individual Microsoft Teams user as long as your bot has user information obtained through previous addition in a personal, groupChat or team scope. This information enables your bot to proactively notify them. For instance, if your bot was added to a team, it could query the team roster and send users individual messages in personal chats, or a user could #mention another user to trigger the bot to send that user a direct message.
See this SO answer for additional help. Note: it's written for a V4 bot, so you may need to make some adjustments.
Let me know if you run into issues and I will adjust my answer accordingly.
I am using code based on https://github.com/Microsoft/BotFramework-WebChat/blob/master/samples/15.d.backchannel-send-welcome-event/index.html
When I load the web page I get two of the welcome messages. Looking at the console output of my bot I can see two conversation updates happening.
This doesn't happen with the Bot framework emulator, which only shows one welcome message.
The only place where my code differs from the sample is in rendering:
window.WebChat.renderWebChat({
directLine: window.WebChat.createDirectLine({ token }),
store,
styleOptions,
userID: guid(),
}, document.getElementById('webchat'));
Why is this hapening? Why is the web channel sending two "join" events for the user?
My code handling conversation updates looks like this:
} else if (turnContext.activity.type === ActivityTypes.ConversationUpdate) {
if (DEBUG) { console.log("ConversationUpdate"); }
// Do we have any new members added to the conversation?
if (turnContext.activity.membersAdded.length !== 0) {
// Iterate over all new members added to the conversation
for (var idx in turnContext.activity.membersAdded) {
console.log(turnContext.activity.membersAdded);
// Greet anyone that was not the target (recipient) of this message
// the 'bot' is the recipient for events from the channel,
// turnContext.activity.membersAdded == turnContext.activity.recipient.Id indicates the
// bot was added to the conversation.
if (turnContext.activity.membersAdded[idx].id != turnContext.activity.recipient.id) {
if (DEBUG) {console.log("Starting MASTER_DIALOG");}
const user = await this.userProfile.get(turnContext, {});
user.id = this.guid();
await this.userProfile.set(turnContext, user);
await this.userState.saveChanges(turnContext);
return await dialogContext.beginDialog(MASTER_DIALOG)
}
}
}
}
Using the ConversationUpdate event for sending a welcome message is not recommended. Read more about how to properly send a greeting message.
There will be two ConversationUpdate events per connection. One for when bot joins the conversation and one for when a (human) user joins the conversation. In your current code you are iterating over all new members, where you have to filter out the bot itself.
A better option would be to make use of a custom event sent using the backchannel. In the example you mention, you already have this functionality. It will sent a new event webchat/join to your bot, which even includes the browser language by default.
Question
I have a simple Bot for MS Teams developed in C# with the Bot Builder SDK 3.15.0.0 targeting .NET framework 4.7.1.
When mentioned, it retrieves the Jira ticket Ids in the message and returns a single reply with a list of Cards, each one displaying a summary of a Jira Issue.
I'd like to know if it's possible to not populate the activity feed when sending the reply with the card attachments as it's not needed for my use case.
Example
This is how I usually build the reply to a user message
var reply = activity.CreateReply();
reply.AttachmentLayout = AttachmentLayoutTypes.List;
reply.Attachments = thumbnailCards;
await context.PostAsync(reply);
And this is what I tried after reading the docs at https://learn.microsoft.com/en-us/microsoftteams/platform/concepts/activity-feed#rest-api-sample
var reply = activity.CreateReply();
reply.AttachmentLayout = AttachmentLayoutTypes.List;
reply.Attachments = thumbnailCards;
reply.ChannelData = JsonConvert.SerializeObject(new
{
notification = new
{
alert = false
}
});
await context.PostAsync(reply);
I was hoping that setting the ChannelData with notification.alert = false would just disable the notifications, but it actually doesn't display any message.
Have you tried using the Teams nuget package: https://www.nuget.org/packages/Microsoft.Bot.Connector.Teams
var reply = activity.CreateReply();
reply.ChannelData = JObject.FromObject(new TeamsChannelData()
{
Notification = new NotificationInfo(false)
});
Source for this package can be found here: https://github.com/OfficeDev/BotBuilder-MicrosoftTeams/
The alert you are getting in the activity feed is simply the "someone replied to your message" alert and is nothing special coming from the bot. This notification in the activity feed cannot be disabled as of now. Other team members won't receive this alert in activity feed unless they are following the same channel.
Sending notification using Rest API is designed to work for 1:1 chat.
Updated
I am developing a Skype bot with 1:1 conversation with Bot Framework.
In that I have a WebHook method which will call from an external service and sends message to my bot, then my bot will send that message to a skype user.
The following code is for v1 in message controller along with api/messages post method
public async Task<Message> Post([FromBody]Message message){}
[Route("~/api/messages/hook")]
[HttpPost]
public async Task<IHttpActionResult> WebHook([FromBody]WebHookMessage message)
{
if (message.Type == "EmotionUpdate")
{
const string fromBotAddress = "<Skype Bot ID here>";
const string toBotAddress = "<Destination Skype name here>";
var text = resolveEmoji(message.Data);
using (var client = new ConnectorClient())
{
var outMessage = new Message
{
To = new ChannelAccount("skype", address: toBotAddress , isBot: false),
From = new ChannelAccount("skype", address: $"8:{fromBotAddress}", isBot: true),
Text = text,
Language = "en",
};
await client.Messages.SendMessageAsync(outMessage);
}
}
return Ok();
}
I will call above WebHook from another service, so that my bot will send messages to the respective skype user.
Can anyone please help me how can I achieve the same in V3 bot framework?
I tried the following but not working
const string fromBotAddress = "Microsoft App ID of my bot";
const string toBotAddress = "skype username";
WebHookMessage processedData = JsonConvert.DeserializeObject<WebHookMessage>(message);
var text = resolveEmoji(processedData.Data);
using (var client = new ConnectorClient(new Uri("https://botname.azurewebsites.net/")
, "Bot Microsoft App Id", "Bot Microsoft App secret",null))
{
var outMessage = new Activity
{
ReplyToId = toBotAddress,
From = new ChannelAccount("skype", $"8:{fromBotAddress}"),
Text = text
};
await client.Conversations.SendToConversationAsync(outMessage);
}
But it is not working, finally what I want to achieve is I want my bot send a message to a user any time how we will send message to a person in skype.
The following code works, but there are some things that are not that obvious that I figured out (tested on Skype channel)
When a user interacts with the bot the user is allocated an id that can only be used from a specific bot..for example: I have multiple bots each using a skype channel. When I send a message from my skype user to bot A the id is different than for bot B. In the previous version of the bot framework I could just send a message to my real skype user id, but not anymore. In a way it simplifies the whole process because you only need the recipient's id and the framework takes care of the rest, so you don't have to specify a sender or bot Id (I guessed all that is linked behind the scenes)
[Route("OutboundMessages/Skype")]
[HttpPost]
public async Task<HttpResponseMessage> SendSkypeMessage(SkypePayload payload)
{
using (var client = new ConnectorClient(new Uri("https://skype.botframework.com")))
{
var conversation = await client.Conversations.CreateDirectConversationAsync(new ChannelAccount(), new ChannelAccount(payload.ToSkypeId));
IMessageActivity message = Activity.CreateMessageActivity();
message.From = new ChannelAccount();
message.Recipient = new ChannelAccount(payload.ToSkypeId);
message.Conversation = new ConversationAccount { Id= conversation.Id };
message.Text = payload.MessageBody;
await client.Conversations.SendToConversationAsync((Activity)message);
}
return Request.CreateResponse(HttpStatusCode.OK);
}
I'm not sure I understand what you're trying to do. If you'd like to answer a message (activity), try something like this:
ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl));
var reply = activity.createReply(text, "en");
await connector.Conversations.ReplyToActivityAsync(reply);
Activity.createReply switches the From and Recipient fields from the incoming activity. You can also try setting these field manually.
UPDATE
You need to create a ConnectorClient to the Skype Connector Service, not to your bot! So try with the Uri http://skype.botframework.com it might work.
However, I don't think you can message a user on Skype without receiving a message from it in the first place (i.e. your bot needs to be added to the user's contacts). Once you have an incoming message from the user, you can use it the create replies, just as described above.
WebHookMessage processedData = JsonConvert.DeserializeObject<WebHookMessage>(message);
var text = resolveEmoji(processedData.Data);
var client = new ConnectorClient(new Uri(activity.serviceUrl));
var outMessage = activity.createReply(text);
await client.Conversations.SendToConversationAsync(outMessage);
activity is a message received from the given user earlier. In this case, activity.serviceUrl should be http://skype.botframework.com, but generally you should not rely on this.
You can try to create the activity (outMessage) manually; for that, I'd recommend inspecting the From and Recipient fields of a message coming from a Skype user and setting these fields accordingly. However, as mentioned before, your bot needs to be added to the user's contacts, so at this point it will have received a message from the user.