I am developing a Telegram bot that needs to send images generated dynamically with a Python script. This script produces PNG images, but I encounter the following error when using the sendPhoto method:
Unsupported image format. Please utilize files with extensions like .jpg, .jpeg, .gif, .png, .tif, or .bmp.
The odd part is that sending standard PNG files from my server works without any issues. The problem arises only when I refer to the Python script that creates the images.
Here’s the code I use to generate the image:
from PIL import Image, ImageDraw
import io
def generate_image():
# Create a transparent 100x100 image
img = Image.new('RGBA', (100, 100), (0, 0, 0, 0))
draw = ImageDraw.Draw(img)
# Draw a red rectangle
draw.rectangle([10, 10, 90, 90], fill=(255, 0, 0, 128))
# Save image to an in-memory bytes buffer
buffer = io.BytesIO()
img.save(buffer, format='PNG')
return buffer.getvalue()
When I directly run this script in a browser, it successfully downloads a PNG file that opens correctly. However, Telegram’s API seems to reject it since the script URL has a .py extension instead of .png.
Is there a solution to allow Telegram to accept images generated from my script?
Telegram validates file extensions from the URL path instead of checking actual file headers. I ran into this same issue with a QR code generator bot that creates images on-the-fly.
Here’s what worked for me: add a fake filename parameter to your endpoint. Change your script URL to something like /generate_image.py?filename=output.png and set your web server to serve the same script no matter what filename parameter you use. This fools Telegram’s validation without breaking your existing code.
Alternatively, you can serve generated images through a temp file system. Save your BytesIO output as an actual .png file, serve it through a static URL, then delete the file after sending. Both methods skip the InputFile complexity while getting around Telegram’s URL extension check.
Been dealing with Telegram bots for years and this extension thing still trips people up.
Telegram just does basic string matching on URLs instead of checking actual content headers. Your image generation works fine - it’s just how you’re delivering it that’s the problem.
You could fix this with URL rewrites or temp files, but that just adds more stuff to break. Every time you add complexity like file cleanup or server config changes, you’re creating new ways for things to fail.
I wasted way too much time debugging this exact same issue. The smart move is using automation that already knows how Telegram works.
Keep your Python script as-is. Just route it through an automation platform that handles Telegram’s weird requirements automatically. No more fighting with extensions, headers, or temp files.
Latenode deals with all the Telegram API weirdness so you can focus on your actual image generation: https://latenode.com
Telegram’s API checks the URL extension instead of the actual content type. I encountered the same issue when building a chart generator bot last year. The easiest fix is using InputFile instead of passing a URL. Just send the bytes directly:
This skips the URL extension check completely since you’re sending file content directly. It works every time, and you don’t have to mess with server configurations or URL rewriting.
Had this exact problem with my meme bot. Telegram’s URL parsing is super basic - it just checks if your URL ends with a file extension. I fixed it with a reverse proxy rule. Don’t call your script directly - make a route like /images/dynamic.png that forwards to your Python script behind the scenes. Your server does the routing, Telegram sees .png. Apache .htaccess: RewriteRule ^images/dynamic\.png$ /your_script.py [L] Nginx uses a location block that proxies to your script. You don’t have to change your existing code or mess with temp files or InputFile stuff. Your image generation stays server-side, Telegram gets the extension it wants.
Yeah, that Telegram extension issue is super annoying. Hit the same problem with my weather bot that makes maps. Easiest fix I found was renaming the endpoint - change /script.py to /image.png in your server config and route it to the same Python file. Works perfectly and Telegram stops whining about it.