Bug Description
slackMrkdwnToMarkdown converts Slack link tokens only when the target starts with http:// or https://. Slack uses the same <target|label> token for mailto: and tel: links, and it auto-links every email address a user types, so ordinary messages contain <mailto:a@b.com|a@b.com>.
The token passes through the converter unchanged. parseMarkdown then reads <mailto:a@b.com|a@b.com> as a CommonMark autolink, which produces a link node whose url is mailto:a@b.com|a@b.com. message.text contains mailto:a@b.com|a@b.com, and stringifyMarkdown(message.formatted) emits the raw Slack token.
Steps to Reproduce
- In Slack, send the bot a message that contains an email address, for example
mail a@b.com please. Slack delivers text: "mail <mailto:a@b.com|a@b.com> please".
- Read
message.text and stringifyMarkdown(message.formatted) in the handler, or run the code sample below, which calls the same converter the adapter uses.
Expected Behavior
A link node with url: "mailto:a@b.com" and text a@b.com, the same treatment <https://…|label> gets. message.text is mail a@b.com please. The same applies to <tel:+15551234567|555-123-4567> and to the unlabelled forms <mailto:a@b.com> and <tel:+15551234567>.
Actual Behavior
Input (event.text) |
link.url |
message.text |
stringifyMarkdown |
mail <mailto:a@b.com|a@b.com> please |
mailto:a@b.com|a@b.com |
mail mailto:a@b.com|a@b.com please |
mail <mailto:a@b.com|a@b.com> please |
call <tel:+15551234567|555-123-4567> now |
tel:+15551234567|555-123-4567 |
call tel:+15551234567|555-123-4567 now |
call <tel:+15551234567|555-123-4567> now |
mail <mailto:a@b.com> please |
mailto:a@b.com |
mail mailto:a@b.com please |
mail <mailto:a@b.com> please |
In the unlabelled case the URL is correct, but the visible text and message.text include the mailto: scheme.
Code Sample
import { SlackFormatConverter } from "@chat-adapter/slack";
import { stringifyMarkdown, toPlainText } from "chat";
const ast = new SlackFormatConverter().toAst("mail <mailto:a@b.com|a@b.com> please");
console.log(toPlainText(ast)); // "mail mailto:a@b.com|a@b.com please"
console.log(stringifyMarkdown(ast)); // "mail <mailto:a@b.com|a@b.com> please\n"
Chat SDK Version
4.30.0
Node.js Version
22.21.1
Platform Adapter
Microsoft Teams, Slack
Operating System
Linux
Additional Context
Workaround we run, applied to the mrkdwn before the converter in a SlackFormatConverter subclass:
const LABELLED_ADDRESS_LINK = /<((?:mailto|tel):[^|<>]+)\|([^<>]+)>/g;
const BARE_ADDRESS_LINK = /<((?:mailto|tel):([^|<>]+))>/g;
export function normalizeSlackMrkdwn(mrkdwn: string): string {
return mrkdwn.replace(LABELLED_ADDRESS_LINK, "[$2]($1)").replace(BARE_ADDRESS_LINK, "[$2]($1)");
}
export class NormalizingSlackFormatConverter extends SlackFormatConverter {
override toAst(mrkdwn: string): Root {
return super.toAst(normalizeSlackMrkdwn(mrkdwn));
}
}
Bug Description
slackMrkdwnToMarkdownconverts Slack link tokens only when the target starts withhttp://orhttps://. Slack uses the same<target|label>token formailto:andtel:links, and it auto-links every email address a user types, so ordinary messages contain<mailto:a@b.com|a@b.com>.The token passes through the converter unchanged.
parseMarkdownthen reads<mailto:a@b.com|a@b.com>as a CommonMark autolink, which produces alinknode whoseurlismailto:a@b.com|a@b.com.message.textcontainsmailto:a@b.com|a@b.com, andstringifyMarkdown(message.formatted)emits the raw Slack token.Steps to Reproduce
mail a@b.com please. Slack deliverstext: "mail <mailto:a@b.com|a@b.com> please".message.textandstringifyMarkdown(message.formatted)in the handler, or run the code sample below, which calls the same converter the adapter uses.Expected Behavior
A
linknode withurl: "mailto:a@b.com"and texta@b.com, the same treatment<https://…|label>gets.message.textismail a@b.com please. The same applies to<tel:+15551234567|555-123-4567>and to the unlabelled forms<mailto:a@b.com>and<tel:+15551234567>.Actual Behavior
event.text)link.urlmessage.textstringifyMarkdownmail <mailto:a@b.com|a@b.com> pleasemailto:a@b.com|a@b.commail mailto:a@b.com|a@b.com pleasemail <mailto:a@b.com|a@b.com> pleasecall <tel:+15551234567|555-123-4567> nowtel:+15551234567|555-123-4567call tel:+15551234567|555-123-4567 nowcall <tel:+15551234567|555-123-4567> nowmail <mailto:a@b.com> pleasemailto:a@b.commail mailto:a@b.com pleasemail <mailto:a@b.com> pleaseIn the unlabelled case the URL is correct, but the visible text and
message.textinclude themailto:scheme.Code Sample
Chat SDK Version
4.30.0
Node.js Version
22.21.1
Platform Adapter
Microsoft Teams, Slack
Operating System
Linux
Additional Context
Workaround we run, applied to the mrkdwn before the converter in a
SlackFormatConvertersubclass: