Отправка сообщений в Telegram из VBA

Использование мессенджеров (Viber, Telegram, WhatsApp) заметно упростило и разнообразило общение людей, позволив все время находится “на связи”, и не быть привязанными к компьютеру. В то же время пользователи мессенджеров получили куда больший функционал чем обычные SMS-сообщения, использование которых у операторов мобильной связи стала куда большей роскошью, нежели интернет трафик.

А что, если приспособить отправку сообщений в мессенджер из VBA кода, привязав к окончанию работы макроса, получению Email или настроить на периодическую отправку сообщений со статусом каких-либо показателей (% выполнения плана продаж, список незакрытых сделок и т.д.)? Не найдя подходящего решения в интернет для VBA, я решил написать свое собственное с использованием Telegram бота, о чем и хочу поделиться в данном посте. Обмолвлюсь сразу же – описанный ниже функционал НЕ ПОЗВОЛЯЕТ вести интерактивный диалог с ботом, а лишь отправлять сообщения пользователю в одностороннем порядке.

И так, приступим. Что первое необходимо сделать чтобы начать тестировать функционал отправки сообщений в Telegram через VBA? Предполагаю, что сам мессенджер у Вас уже установлен и поэтому данный этап пропустим )). Опишем следующую этапность действий:

  1. Создадим Telegram бота
  2. Напишем VBA-класс для отправки сообщений ботом
  3. Используем класс в нашем коде
  1. Создание Telegram бота

Сначала, необходимо настроить бота, через которого Вы будете отправлять сообщения. Для этого a) Найти в Telegram пользователя @BotFather и начните диалог с помощью кнопки Start

telegramvba_a

b) Отправьте боту команду /newbot, которая отвечает за создание новых ботов

telegramvba_b

c) Задайте имя своего нового бота согласно инструкциям и подсказкам

telegramvba_c

telegramvba_c2

telegramvba_d

d) Получите токен для вашего бота в ответном письме @BotFather (см. рис. выше) e) Найдите своего бота в мессенджере и начните переписку

telegramvba_e

telegramvba_e3

f) Получите ID чата (вашей переписки с ботом). Для этого в окне браузера введите следующую команду:

https://api.telegram.org/bot<Bot_token>/getUpdates

где <Bot_token> – это токен, полученный от @BotFather.

В нашем тестовом примере токен был 781500114:AAECOTrby1zuQ0afGozyRlvua5CMGezT9IA Таким образом, получим следующую строку:

https://api.telegram.org/bot781500114:AAECOTrby1zuQ0afGozyRlvua5CMGezT9IA/getUpdates

При переходе по указанному адресу, браузер выдаст ответ в котором содержится необходимая информация – id чата

g) Сохраните данные о токене и chat ID для дальнейшего использования в скрипте

  1. Написание класса для отправки сообщений ботом

Задумка написания класса для отправки ботом сообщений была следующая: указываем имя бота, указываем имя получателя, текст сообщения и отправляем месседж. Для этого имя бота и получателя зададим как свойства класса, для того, чтобы можно было обращаться к ним не по токену и id, а по именам.

Private ms_current_chatbot      As String
Private ms_current_user         As String

Public Property Let ChatBot(ByVal Value As String):         ms_current_chatbot = Value:         End Property
Public Property Get ChatBot() As String:                    ChatBot = ms_current_chatbot:       End Property
Public Property Let UserName(ByVal Value As String):        ms_current_user = Value:            End Property
Public Property Get UserName() As String:                   ChatBot = ms_current_user:          End Property

Таким образом мы определили два свойства: ChatBot, UserName с помощью которых мы будем задавать нашему классу два входящих параметра: имя нашего бота и имя получателя. Сами значения токена и id будем получать на основе заданных имен отдельными функциями внутри класса (они не будут видны извне):

Private Function getChatToken() As String
'********************************
'Purpose:       Function retrieves token for bot
'Result:        getChatToken gets value of token
'********************************
If Len(ms_current_chatbot) > 0 Then
    Select Case ms_current_chatbot
        '---- other cases can be added below here ----
        Case "OfficeScripts_test":      getChatToken = "781500114:AAECOTrby1zuQ0afGozyRlvua5CMGezT9IA"
        Case Else:                      getChatToken = vbNullString
    End Select
Else:   getChatToken = vbNullString
End If
End Function
Private Function getChatID() As String
'********************************
'Purpose:       Function retrieves user chat id
'Result:        getChatID gets value of chat id
'********************************
If Len(ms_current_user) > 0 Then
    Select Case ms_current_user
        '---- other cases can be added below here ----
        Case "Aleksandr": 		getChatID = "xxxxxxxxx" 'Substitute xxxxxxxxx with your real ID
        Case Else:              getChatID = vbNullString
    End Select
Else:   getChatID = vbNullString
End If
End Function

Осталось описать главную часть нашего класса – функцию отправки сообщения. Для того чтобы отправить сообщение, необходимо сформировать строку определенного формата и отправить ее на сервер Telegram. Часть строки будет всегда неизменной, и поэтому ее логично задать константой, а другие части зададим переменными, из которых и будем формировать строку.

Постоянную часть определим константой TELEGRAM_URL:

Private Const TELEGRAM_URL As String = “https://api.telegram.org/bot"

А прочие части будем строки (URL) формировать на лету следующим образом:

'//Getting URL string
URL = TELEGRAM_URL & getChatToken & "/sendMessage?" & _
"chat_id=" & getChatID & "&" & _
"text=" & BodyText

Для отправки сообщения будем использовать библиотеку MSXML2, которая должна будет инициализироваться при определении класса. Сохраним ее в переменную mobj_httpRequest , которой и будем передавать нашу строку URL.

Есть, однако, один нюанс, который нельзя не озвучить: Строка URL должна быть совместима с WEB стандартами (не содержать пробелов, спец.символов и т.д.) и для этого ее необходимо конвертировать в нужный нам стандарт. Для этого я воспользовался функцией URLEncode пользователя parkone на GitHub и конвертировал сообщение перед отправкой с помощью этой функции.

Public Function sendMessage(ByVal BodyText As String) As Boolean
'********************************
'Purpose:       Function sends telegram message to user
'Arguments:     BodyText - message text
'Result:        True - message was sent successfully
'               False - message wasn't sent
'********************************
Dim URL             As String
Dim iCount          As Integer

If Not mobj_httpRequest Is Nothing Then
    If Len(ms_current_chatbot) > 0 And Len(ms_current_user) > 0 Then
        
    '//Converting chars to url format
    BodyText = URLEncode(BodyText)
    
    '//Getting URL string
    URL = TELEGRAM_URL & getChatToken & "/sendMessage?" & _
          "chat_id=" & getChatID & "&" & _
          "text=" & BodyText
    
    mobj_httpRequest.Open "POST", URL, True
    mobj_httpRequest.Send
    
    On Error Resume Next
    iCount = 0
    Do Until mobj_httpRequest.Status = 200 And mobj_httpRequest.ReadyState = 4
        iCount = iCount + 1
        If iCount = MAX_TRY_COUNT Then
            Exit Do
        End If
    Loop
    On Error GoTo 0
    
    If iCount < MAX_TRY_COUNT Then
            sendMessage = True
    Else:   sendMessage = False
    End If
Else
    '//Chat not specified
    If Not SILENT_MODE Then
        MsgBox "Chat or User haven't been set. Please specify chat & user firstly", vbExclamation + vbOKOnly
    End If
    sendMessage = False
End If

Else
    '//MSXML object is not initialized
    If Not SILENT_MODE Then
        MsgBox "Http connection was lost", vbExclamation + vbOKOnly
    End If
    sendMessage = False
End If

End Function

В случае, если при отправке сообщения произошел сбой в интернет соединении, недоступность сервера и т.д. и наш запрос не был доставлен, в функции sendMessage имеется цикл, который будет повторяться несколько раз (до установленного Вами значения количества попыток), пока не отправит сообщение. Данные строки выделены подсветкой выше.

  1. Использование класса

В самом начале, когда нами создавался класс для отправки сообщений Telegram, ему было присвоено имя по умолчанию, которое лучше изменить на что-то более значащее и понятное. Я присвоил классу имя clTelegramNotifier. Использовать его в коде довольно просто, если изначально был четко определен желаемый алгоритм работы, о чем было написано в начале второго раздела. Мы хотели задать имя получателя, имя бота, указать какой текст мы хотим отправить и получить наше сообщение на телефоне, что мы в итоге и сделали.

Sub test_telegram()
Dim Telegram   As clTelegramNotifier
Dim text       As String

Set Telegram = New clTelegramNotifier

If Telegram.Initialized Then

Telegram.ChatBot = "OfficeScripts_test"
Telegram.UserName = "Aleksandr"
text = [b2].Value2
If Telegram.sendMessage(text) Then
Debug.Print "OK"
End If

End If
Set Telegram = Nothing

End Sub

Данную процедуру в рамках тестирования я поместил на кнопку на листе и передавал ей как параметр текст из ячейки [B2]. Результат видно на рисунке ниже. А сам класс можно скачать в конце данного поста.

final_test

VBA  excel 

Смотрите также