DEV Community

Cover image for Telegram Newsletter Command
Tom Witkowski
Tom Witkowski

Posted on • Originally published at gummibeer.dev

Telegram Newsletter Command

After I've published my first post and got kind feedback from several readers I wanted to add something like a newsletter for my blog.

My goal is that it should inform the subscribers short after a post is published about the new post. Emails aren't an option as I hate emails and it's also not that easy and cheap to potentially scale them.
So I've searched for a different solution and thought about Telegram which has a powerful but still easy API and even creating a bot is as easy as sending messages to BotFather.

The next criteria are that I don't have any permanently running app for this site and my content is stored in markdown files. So it should work without any database and I need a runner that allows me to schedule commands.
The runner was quickly found, the same that deploys this site and does some checks - GitHub Actions.

Setting up Telegram

That's probably the easiest part as you only send some messages and have to create a new Telegram channel.

Bot

The commands I've sent to BotFather:

/newbot
/setdomain
/setuserpic
/setabouttext
Enter fullscreen mode Exit fullscreen mode

After I've followed all the instructions I had my own GummibeerBot.

Channel

So now we need a channel that the bot will send the messages to. That's possible via the normal UI.
You must create a public channel as bots can't send messages to private channels. And you also want others to be able to join easily - otherwise it wouldn't be a newsletter. 😉

After you've created your channel you must add the bot as an administrator with the ability to send messages.
To do so open the channel => click on the name => click on administrators and add a new one.

Console Command

I've used artisan make:command PromotePost to create my new command - you can adjust the name however you want it.

Our command has to do two things:

  1. pick a post to promote - it has to be published, should be promotable and shouldn't be promoted earlier
  2. generate the message and send it to the Telegram channel

Configuration

At first we have to configure our app to know about some secrets that shouldn't be part of our app code.

I will use the services config as it's perfect for simple service configurations like Telegram in this case.
I will add the bot_token (you've received during setting up the Telegram bot and the Telegram channel chat_id.

'telegram' => [
    'bot_token' => env('TELEGRAM_BOT_TOKEN'),
    'chat_id' => '-xxxxxxxxxx',
],
Enter fullscreen mode Exit fullscreen mode

The token is a secret you shouldn't share with anyone - so using the .env here is a good choice.
The chat ID isn't secret so it's up to you if you want to be able to adjust it via .env or not. Using env here would be useful if you want to use a test channel during development for example.

To retrieve the chat ID I've used a trick as the ID isn't copyable somewhere in the Telegram app.

You should send a message to your bot in the channel you want him to send the messages in - I've used @GummibeerBot test.
After this you should run the following code - Tinkerwell will be perfect for this but you can also use normal tinker or however you run one-shot code.

$chatId = Http::get(sprintf(
    'https://api.telegram.org/bot%s/getUpdates',
    config('services.telegram.bot_token')
))->json()['result'][0]['channel_post']['chat']['id'];
Enter fullscreen mode Exit fullscreen mode

This should return the chat ID which looks something like -xxxxxxxxxx.

Picking your post

This part depends massively on your way you manage your posts and which attributes you use.
I've added a should_promote boolean attribute that indicates if this post should be promoted and a promoted_at datetime attribute that will indicate when/if the post was already promoted.
With these attributes you can use database query or collection filters to reduce your dataset.
As I only want to promote one post at a time I'm using this snippet to get the post I want to send out.

$post = $posts->sortBy('created_at')->first();
Enter fullscreen mode Exit fullscreen mode

Send message via Telegram

That's the most important part but it's still not complicated thanks to Laravel Http helper class.

To send a message via Telegram you have to use the sendMessage endpoint.

use Illuminate\Support\Facades\Http;
use Spatie\Emoji\Emoji;

$response = Http::post(
    sprintf('https://api.telegram.org/bot%s/sendMessage', config('services.telegram.bot_token')),
    [
        'chat_id' => config('services.telegram.chat_id'),
        'text' => Emoji::orangeBook().' '.$post->title.PHP_EOL.$post->url,
    ]
);
Enter fullscreen mode Exit fullscreen mode

I'm using the spatie/emoji package here to get the "📙" emoji and append the post title and after a line break the URL to the post (be sure that your code generates an absolute URL to your production system).

That's it - you've already sent the message to your Telegram channel and should see a message in it.

After this you should update/save your promoted post to prevent it from being sent out multiple times.

For everyone interested to see it in action you can join my Telegram Newsletter channel.

Top comments (0)