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.
The commands I've sent to BotFather:
/newbot /setdomain /setuserpic /setabouttext
After I've followed all the instructions I had my own
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.
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:
- pick a post to promote - it has to be published, should be promotable and shouldn't be promoted earlier
- generate the message and send it to the Telegram channel
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
'telegram' => [ 'bot_token' => env('TELEGRAM_BOT_TOKEN'), 'chat_id' => '-xxxxxxxxxx', ],
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
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']['channel_post']['chat']['id'];
This should return the chat ID which looks something like
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();
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, ] );
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.