I’m writing a Telegram bot in Julia and I can’t figure out how to send files correctly.
I’ve seen similar questions for other languages but it wasn’t helpful.
Currently, I have such function:
function sendDoc(chat, fileName::String)
file = open(fileName)
url = string(base_url, "sendDocument")
mp = HTTP.Multipart(basename(fileName), file)
query = Dict("chat_id" => chat)
HTTP.post(url; query=query, files=Dict("document" => mp))
close(file)
end
I try it on a simple test.txt
file with the content abc
so the size of a file or it’s name can’t be a reason for any errors.
What I get from it (and also in case if I use file
instead of mp
) is an HTTP 400 error (I removed some parts for privacy purposes):
ERROR: LoadError: HTTP.ExceptionRequest.StatusError(400, "POST", "/bot/sendDocument?chat_id=", HTTP.Messages.Response(v"1.1.0", 400, Pair{SubString{String},SubString{String}}["Server" => "nginx/1.16.1", "Date" => "Thu, 12 Mar 2020 GMT", "Content-Type" => "application/json", "Content-Length" => "94", "Connection" => "keep-alive", "Strict-Transport-Security" => "max-age=31536000; includeSubDomains; preload", "Access-Control-Allow-Origin" => "*", "Access-Control-Expose-Headers" => "Content-Length,Content-Type,Date,Server,Connection"], UInt8[0x7b, 0x22, 0x6f, 0x6b, 0x22, 0x3a, 0x66, 0x61, 0x6c, 0x73 … 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x7d], HTTP.Messages.Request("POST", "/bot/sendDocument?chat_id=", v"1.1.0", Pair{SubString{String},SubString{String}}["Host" => "api.telegram.org", "User-Agent" => "HTTP.jl/1.3.1", "Content-Length" => "0"], UInt8[], HTTP.Messages.Response(#= circular reference @-2 =#), 1, nothing)))
I also tried putting mp
or file
in body
instead of files
but then I get the following:
┌ Info: Error in @async writebody task. Server likely closed the connection unexpectedly. Only an issue if unable to read the response and this error gets re-thrown.
│ exception =
│ MethodError: no method matching write(::HTTP.Streams.Stream{HTTP.Messages.Response,HTTP.ConnectionPool.Transaction{MbedTLS.SSLContext}}, ::Pair{String,IOStream})
│ Closest candidates are:
│ write(::IO, ::Any) at io.jl:582
│ write(::IO, ::Any, ::Any...) at io.jl:584
│ write(::IO, ::Complex) at complex.jl:217
Including the file in query
is also something I could try but then it would be in the URL and I’d be very limited in file size.
The 400 error looks the same as if it would be missing a field, so I assume that Telegram can’t see the Dict("document" => mp)
, but at the same time error includes UInt8[0x7b, … 0x7d]
which looks like the contents of the file. How do I make it right?
3
Answers
Turns out, it's not
HTTP.Multipart
that I needed, it'sHTTP.Form
.The following function works:
Let’s say you have a photo in your directory "Foto.jpg". To send a photo, you would need this:
Where ‘bot_manu’ should be your chat id, ‘bot_token’ is the bot id token. Hope this helps for those who wanted to send a photo. To get ‘bot_manu’ and ‘bot_token’ I used BotFather.
If you want to, you may use Telegram.jl package, which in particular includes support for document and images sending.
You can do it like this
Here
bot_token
andchat
are bot token and chat id.