How to send images from URLs using a Telegram bot

I created a Telegram bot that’s supposed to send pictures from web links when asked. I’m using the pyTelegramBotAPI library. I tried it with a test image URL, but it didn’t work. I got this error:

telebot.apihelper.ApiException: sendPhoto failed. Returned result: <Response [400]>

I’m not sure what’s wrong. Can someone help me figure out how to make my bot send images from URLs? Here’s my code:

import telebot
import time
import requests
from io import BytesIO

BOT_TOKEN = 'your_token_here'
IMAGE_URL = 'https://example.com/test-image.jpg'

def handle_messages(messages):
    for msg in messages:
        if msg.text and msg.text.startswith('/picture'):
            chat_id = msg.chat.id
            try:
                image_data = BytesIO(requests.get(IMAGE_URL).content)
                bot.send_chat_action(chat_id, 'upload_photo')
                bot.send_photo(chat_id, image_data, reply_to_message_id=msg.message_id)
            except Exception as e:
                print(f'Error sending photo: {e}')

bot = telebot.TeleBot(BOT_TOKEN)
bot.set_update_listener(handle_messages)
bot.polling(none_stop=True)

Did I miss something? Any ideas on how to fix this?

I’ve dealt with this exact problem before. The issue is likely how you’re handling the image data. Instead of using BytesIO, try this approach:

  1. Download the image to a temporary file
  2. Send the file to Telegram
  3. Clean up the temporary file

Here’s a modified version of your code that should work:

import tempfile
import os

def handle_messages(messages):
    for msg in messages:
        if msg.text and msg.text.startswith('/picture'):
            chat_id = msg.chat.id
            try:
                response = requests.get(IMAGE_URL)
                if response.status_code == 200:
                    with tempfile.NamedTemporaryFile(delete=False, suffix='.jpg') as temp_file:
                        temp_file.write(response.content)
                        temp_file_path = temp_file.name
                    
                    bot.send_chat_action(chat_id, 'upload_photo')
                    with open(temp_file_path, 'rb') as photo:
                        bot.send_photo(chat_id, photo, reply_to_message_id=msg.message_id)
                    
                    os.remove(temp_file_path)
                else:
                    print(f'Failed to download image. Status code: {response.status_code}')
            except Exception as e:
                print(f'Error sending photo: {e}')

This method has worked reliably for me in similar scenarios. It creates a temporary file, writes the image data to it, sends that file to Telegram, and then cleans up afterward. Give it a try and let me know if it solves your problem.

hey, i had a similar issue. try this:

  1. download image first
  2. open file and send to telegram
response = requests.get(IMAGE_URL)
with open('temp.jpg', 'wb') as f:
    f.write(response.content)
bot.send_photo(chat_id, open('temp.jpg', 'rb'))

this worked 4 me. hope it helps!

I’ve encountered this issue before. The problem might be with how you’re handling the image data. Instead of using BytesIO, try downloading the image to a temporary file first. Here’s a modified version of your code that should work:

import os
import tempfile

 def handle_messages(messages):
     for msg in messages:
         if msg.text and msg.text.startswith('/picture'):
             chat_id = msg.chat.id
             try:
                 response = requests.get(IMAGE_URL)
                 if response.status_code == 200:
                     with tempfile.NamedTemporaryFile(delete=False, suffix='.jpg') as temp_file:
                         temp_file.write(response.content)
                         temp_file_path = temp_file.name
                     
                     bot.send_chat_action(chat_id, 'upload_photo')
                     with open(temp_file_path, 'rb') as photo:
                         bot.send_photo(chat_id, photo, reply_to_message_id=msg.message_id)
                     
                     os.unlink(temp_file_path)
                 else:
                     print(f'Failed to download image. Status code: {response.status_code}')
             except Exception as e:
                 print(f'Error sending photo: {e}')

This approach creates a temporary file, writes the image data to it, and then sends that file to Telegram. It also cleans up the temporary file afterward. This method has worked reliably for me in similar scenarios.