vercel / vercel/chat

Slack: inbound `<mailto:…|label>` and `<tel:…|label>` links are not converted, so the label ends up inside the link URL

Open Beginner friendly
#955 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
TypeScript
Stars
2.4k
Forks
314
Avg merge
1d 18h
Merged PRs (30d)
63

Description

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
  1. 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".
  2. 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));
  }
}

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at SlackFormatConverter.toAst, which currently handles Slack link tokens only for HTTP targets. Reproduce the labelled and unlabelled mailto: and tel: examples from the issue, then verify that the resulting link URL, visible text, message.text, and stringifyMarkdown output match the expected behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
74/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.