Telegram

A connector for Telegram.

⚠️ Breaking Changes introduced in opsdroid 0.20.0

We have moved this connector from calling the API to get updates, to subscribe to webhook events. This means that if you are running this connector in older versions, the connector will receiving updates from Telegram.

Migration requirements

  • expose opsdroid to the web through a secure connection (https) - you can use ngrok to forward your traffic through a secure url.

  • Include the following in your opsdroid configuration

web:
  base-url: <secure url/ngrok url>

If you need any help migrating, please asks on our matrix channel.

Requirements

  • A Telegram account - to create a bot

  • A Bot API Token

  • A secure URL where opsdroid is running (could be forwarded by ngrok)

Note: To register a new bot, open Telegram, write @BotFather and type /newbot. Provide a name and username (ending in bot) and BotFather will give you your API Token.

Configuration

web:
  base-url: <https://your-opsdroid-url-or-ngrok-url>

connectors:
  telegram:
    # required
    token: "123456789:ABCDEFGHIJKLMNOPQRSTUVWXYZ-ZYXWVUT"  # Telegram bot token
    # optional
    bot-name: opsdroid # Name to be used by the bot in some replies, defaults to opsdroid
    reply-unauthorized: True # Should the bot reply to unauthorized users?
    whitelisted-users:  # List of users who can speak to the bot, if not set anyone can speak
      - user1
      - user2

Note: You MUST specify the base-url in the web config, otherwise opsdroid won’t be able to receive webhook notifications.

Usage

You can add this connector to:

  • Direct Messages

  • Groups

  • Channels

If you want opsdroid to work on your group or channel, you should add it by opening your channel/group details and select the Add Members button, then search for your bot username and add it. It’s a good idea to add the bot as admin, because in some cases where you have privacy active, opsdroid won’t be able to read user’s names.

Direct Messages

To interact with your bot directly, start a new message, click search and type your bot name. For example, if you named your bot: MyAwesome_Bot you can just search for that name and wait for the result to show up, then click on the name of your bot and a new chat window will start. You can now talk with your bot and give him commands.

[6:13:11 PM] Fabio:
hello

Unread messages
[6:13:12 PM] opsdroid:
Hi FabioRosado

If you are using a list of users that can interact with the bot by using the configuration parameter whitelisted-users, you might want to set the parameter reply-unauthorized to True to make opsdroid reply to an unauthorized user, that the user can’t interact with the bot.

Groups

Opsdroid will listen to every message sent to a group, so it’s a good idea to set a list of users that can interact with the bot if you are using opsdroid skills that some users shouldn’t be able to trigger.

To set up a list of users that can interact with the bot, you can set the option configuration parameter whitelisted-users - you should try to use the user id obtained from Telegram response. Also, if you set up the configuration parameter reply-unauthorized you might want to set it to false so the bot doesn’t send a message every time someone says something to the group.

Channels

By default Telegram doesn’t show the name of the user that sends messages to a channel, if you want to change this behaviour, you can open your channel, click the channel name to open the settings, chose edit and toggle the option Sign Messages.

Note: If you have a discussion group, opsdroid will reply to any command sent to a channel in that group.

Whitelisting users

This is an optional config option that you can include on your config.yaml to prevent unauthorized users to interact with your bot. Currently, you can specify a user nickname or a userID. Using the userID method is preferable as it will increase the security of the connector since users can’t change this ID.

Here is how you can whitelist a user:

  telegram:
    token: <your bot token>
    whitelisted-users:
      - user1
      - 124324234 # this is a userID

Finding your userID is not straight forward. This value is sent by Telegram when a user sends a private message to someone (the bot in this case) or when someone calls the getUpdate from the API. To find a userID by a private message, set the logging level to debug and start a new private message to the bot. You will see the API response on your console - it will look similar to this:

{
   "update_id": 539026743,
   "message": {
      "message_id": 109,
      "from": {
         "id": 4532189818,
         "is_bot": false,
         "first_name": "user",
         "language_code": "en"
      },
      "chat": {}
   }
}

Use the id value from the message["from"] field and add it to your whitelisted-users config option.

Parsing images/videos/files

Unfortunately, we are unable to parse any of these formats, the reason for that is because Telegram doesn’t send us any real useful information that we can feed to opsdroid. When you send an image to a channel, Telegram sends us a file id, format and sizes, but no URL or anything that we could use to download the image.

Events Available

The Telegram Connector contains a few events that you can access on your skills. These events were created to allow you to use these messages types on your custom made skills.

class opsdroid.connector.telegram.events.Poll(poll, question, options, total_votes, *args, **kwargs)

Event class that triggers when a poll is sent.

class opsdroid.connector.telegram.events.Contact(contact, phone_number, first_name, *args, **kwargs)

Event class that triggers when a contact is sent.

class opsdroid.connector.telegram.events.Location(location, latitude, longitude, *args, **kwargs)

Event class that triggers when a location message is sent.

class opsdroid.events.JoinGroup(user_id=None, user=None, target=None, connector=None, raw_event=None, raw_parses=None, event_id=None, linked_event=None)

Event to represent joining a group (not a room).

The group could be a slack team or a matrix community.

class opsdroid.events.LeaveGroup(user_id=None, user=None, target=None, connector=None, raw_event=None, raw_parses=None, event_id=None, linked_event=None)

Even to represent leaving a group(not a room).

The group could be a slack team, matrix community or a telegram group.

class opsdroid.events.PinMessage(user_id=None, user=None, target=None, connector=None, raw_event=None, raw_parses=None, event_id=None, linked_event=None)

Event to represent pinning a message or other event.

class opsdroid.events.Reply(text, *args, **kwargs)

Event class representing a message sent in reply to another Message.

The linked_event property should hold either an opsdroid.events.Event class or an id for an event to which this message is replying.

class opsdroid.events.EditedMessage(*args, **kwargs)

A opsdroid.events.Message which has been edited.

The linked_event property should hold either an opsdroid.events.Event class or an id for an event to which the edit applies. The linked_event for Slack is the ts (timestamp) of the message to be edited

Reference

class opsdroid.connector.telegram.ConnectorTelegram(*args, **kwargs)

A connector for the chat service Telegram.

build_url(method)

Build the url to connect to the API.

Parameters

method (string) – API call end point.

Returns

String that represents the full API url.

async connect()

Create route and subscribe to Telegram webhooks.

The first thing we do on connect is to set up the route to receive events from Telegram, we also pass some arguments to the webhook to get events from messages, edited messages, channel posts and update id which is basically the event id.

One thing that is worth mentioning here, is that Telegram doesn’t implement a request authenticity policy, instead they suggest that we use our token on the webhook route, but using the token on the url doesn’t seem like a good idea, we are instead generating a strong pseudo-random string using the secrets library and add that string to our webhook route.

async disconnect()

Delete active webhook.

If we terminate opsdroid, we should delete the active webhook, otherwise Telegram will keep pinging out webhook for a few minutes before giving up.

static get_user(response, bot_name)

Get user from response.

The API response is different depending on how the bot is set up and where the message is coming from.

Since Telegram sends different payloads, depending of where the message is being sent from, this method tries to handle all the cases.

If the message came from a channel, we use either the author_signature or the bot name for the user and use the message_id for the user_id, this is because channel posts don’t contain users.

Similarly, if a message was posted on a channel, Telegram will forward it to a group - if it was created from the channel. So we handle the case where there is a forward_signature in the payload otherwise we use the bot name.

Parameters
  • response (dict) – Response returned by aiohttp.ClientSession.

  • bot_name (str) – Name of the bot used in opsdroid configuration.

Returns

Extracted username and user id

Return type

string, string

async handle_messages(message, user, user_id, update_id)

Handle text messages received from Telegram.

Here we create our opsdroid events depending of the type of message that we get from Telegram.

Unfortunately, telegram doesn’t give much information when the message is an image, video, sticker or documents. It only give us back the file id, sizes, formats and that’s it. Since we can’t really use any of this information to make opsdroid parse the message, we decided to just log a message in debug mode with the payload and return None.

Parameters
  • message (dict) – The payload received from Telegram

  • user (string) – The name of the user that sent the message

  • user_id (int) – The unique user id from the user that send the message

  • update_id (int) – The unique id for the event sent by Telegram

Returns

Will only return none if it’s an event we can’t parse.

Return type

opsdroid.event or None

handle_user_permission(response, user, user_id)

Handle user permissions.

This will check if the user that tried to talk with the bot is allowed to do so. It will also work with userid to improve security.

async listen()

Listen method of the connector.

Since we are using webhooks, we don’t need to implement the listen method.

async send_file(file_event)

Send File to Telegram.

Gets the chat id from the channel and then sends the bytes of the file as multipart/form-data.

async send_image(file_event)

Send Image to Telegram.

Gets the chat id from the channel and then sends the bytes of the image as multipart/form-data.

async send_message(message)

Respond with a message.

Parameters

message (object) – An instance of Message.

async telegram_webhook_handler(request)

Handle event from Telegram webhooks.

This method will try to handle three different kinds of events:

  • Edited messages

  • Messages

  • Channel posts

Since the payload is pretty much the same both for channel posts and messages we are using the same method to handle both of these events.

We also check the permissions of the user that talked with the bot, if the user has permissions then the event is parsed, if not we either send a message saying that the user can’t talk with the bot or just keep silent.

Parameters

request (aiohttp.web.Request) – Request made to the post route created for webhook subscription.

Returns

Send a received message and a status 200 back to Telegram.

Return type

aiohttp.web.Response