SPFx – Post HTML message to Team chat

2020-03-27

We are continuing the last post´s topic which was integrating Teams and SharePoint Framework. Today we cover the scenario of posting an HTML formatted message to a chat channel in a Team. In a recent application at my customer, we included the option of not only sending emails but also posting messages to the Team´s chat. Since both emails and chat can use inline styling, we can re-use the same code for both scenarios. First off, the solution will require write permissions on groups:

"webApiPermissionRequests": [      
      {
          "resource": "Microsoft Graph",
          "scope": "Group.ReadWrite.All"
      }      
]

Our component will need webpart context and the id of the unified group. From the starter file you will find the unified group id. As long as the webpart is hosted in a group context:

if (this.context.pageContext.site.group && 
    this.context.pageContext.site.group["id"] && this.context.pageContext.site.group["id"]["_guid"]) {
    elemProps.unifiedGroupId = this.context.pageContext.site.group["id"]["_guid"];
}

For demonstration purposes I have merged the remaining code into one file so it should be easy to recreate into your own structure. You can download the complete file from Github. We start with a simple component which enables us to post the message:

export interface IDemoPostToTeamChannelProps {
    context: WebPartContext;    
    unifiedGroupId: string;
}

export const DemoPostToTeamChannel: React.FC<IDemoPostToTeamChannelProps> = ({context, unifiedGroupId}) => {
    const cellStyle = `padding:10px;border:1px solid #ccc;`;
    const msg = `
        <table>
            <tr>
                <th style="${cellStyle}">Heading 1</th>
                <th style="${cellStyle}">Heading 2</th>
            </tr>
            <tr>
                <td style="${cellStyle}">Value 1</td>
                <td style="${cellStyle}">Value 2 with <b>formatting</b></td>
            </tr>
        </table>
    `;

    const post = async () => {
        const demoRepository = new DemoGraphRepository(context, unifiedGroupId);
        const result = await demoRepository.postToChannel(msg);

        console.log(result);
    }

    return <button onClick={post}>Post Message</button>;
};

We have a hardcoded message along with some inline styling. As mentioned earlier, sending the content as an email will achieve the same look. What happens next is that we will first need to get the channel id. We fetch all channels for the team, if no name has been submitted, we will pick the first one. Endpoint for getting the channels:

client.api(`teams/${groupId}/channels/`).get();
const channels = await this._repository.getChannelsForTeam(this._unifiedGroupId);

if (channels && channels.value && channels.value.length > 0) {
    let channel = channels.value.filter(x => x.displayName === channelName || "General")[0];
    
    if (!channel) {
        channel = channels.value[0];
    }
}

Once we have the channel id we can post the message. Message body will look like this:

const chatMsg = {
    body: {
        contentType: "html",
        content: msg
    }
};

Our post method:

public postToChannel = async (groupId: string, chatMsg: Object, channelId: string) : Promise<any> => {
    const client = await this.getGraphClient();
    const result = await client.api(`teams/${groupId}/channels/${channelId}/messages`).post(chatMsg)
    return result;
}

And voila, a message has been posted: Result in Teams