What is the correct code that I need to use to send one or more files of any type along with other parameters using Indy's idHTTP.post? (using Delphi 2009 and Indy 10)
The post in question calls a function in a commercial company's API (ElasticEmail) that sends out emails to the recipients held in one of the parameters. (A link to the documentation on the function I am calling is here. I have example code in C# and other languages from the company here and I have tried to replicate that code in my Delphi code below.
If, in Procedure btnSendbyElastic, I comment out the line Filenames.add(Afilename);
so that the function Upload makes no attempt to attach a file,then the correct call seems to be made as the email gets sent successfully by the API.
However, if I leave that line in so that the lines in function UpLoad
MimeStr := GetMIMETypeFromFile(filenames[i]);
FormData.Addfile('file'+inttostr(i), filenames[i],MIMEStr);
do get executed, then no email is sent and the response from the server is
{"success":false,"error":"One of files has invalid characters in file name."}
(The file Afilename does exist at that location and I have tried with single and double backslashes)
Reading other SO posts on this topic I also tried replacing the file processing loop in Function UpLoad with the following loop instead
for i := 0 to filenames.Count - 1 do
begin
MimeStr := GetMIMETypeFromFile(filenames[i]);
FormData.AddFile('file'+inttostr(i), filenames[i],MIMEStr);
AttachmentContent := TFileStream.Create(filenames[i],fmOpenRead);
try
FormData.AddFormField(AttachmentContent.ToString,filenames[i]);
finally
AttachmentContent.free;
end;
end;
This time, even with a filename specified in Filenames.add(Afilename);
, the email is sent correctly but the recipient sees no attachment.
Among many others, I have read these possible duplicate SO questions
Post a file through https using indy / delphi components
posting a file as part of a form
Nodejs POST request multipart/form-data
and in particular
Using the Indy TidHttp component to send email file attachments through sendgrid
(which is almost exactly what I am trying to do) but I still cannot see what I am doing wrong in my code and what I need to do to correct it.
Here is the code I am using (UPPER_CASE identifiers are constants defined elsewhere)
PS I'm in the UK so apologies for the time delay in responding to US comments/answers
function TForm1.Upload(url: string; params, filenames: Tstringlist): string;
var
FormData : TIdMultiPartFormDataStream;
MIMEStr, ResponseText : string;
i : integer;
begin
try
FormData := TIdMultiPartFormDataStream.Create;
for i := 0 to params.Count - 1 do
FormData.AddFormField(params.Names[i],params.values[params.Names[i]]);
for i := 0 to filenames.Count - 1 do
begin
MimeStr := GetMIMETypeFromFile(filenames[i]);
FormData.Addfile(filenames[i], filenames[i],MIMEStr);
end;
ResponseText :=IdHTTP1.Post(url, FormData);
Memo1.Text := ResponseText; //debug
finally
FormData.free;
end;
end;
procedure TForm1.btnSendbyElastic(Sender: TObject);
var
Params, Filenames : Tstringlist;
url, Afilename : string;
begin
Afilename := 'C:\\Users\\Admin\\Documents\\arrival and departure small.pdf';
Params := Tstringlist.Create;
Filenames := Tstringlist.Create;
try
Params.add('apikey=' + ELASTIC_MAIL_API_KEY) ;
Params.add('from=' + ELASTIC_EMAIL_FROM_EMAIL) ;
Params.add('fromname=' + ELASTIC_EMAIL_FROM_NAME) ;
Params.add('Subject=' + 'The Subject') ;
Params.add('bodyHtml=' + '<h1>Html Body</h1>') ;
Params.add('bodyText=' + 'Text Body') ;
Params.add('to=' + THE_RECIPIENT_ADDRESS) ;
Filenames.add(Afilename); //*** comment out this line and an email is sent correctly
url := ELASTIC_EMAIL_EMAIL_SEND ;
Upload (url , params, filenames );
finally
Params.free;
Filenames.free;
end;
The function GetMIMETypeFromFile
is defined in the Indy unit idGlobalProtocols. I didn't write it, I just call it. But I have reproduced it here as requested
function GetMIMETypeFromFile(const AFile: TIdFileName): string;
var
MIMEMap: TIdMIMETable;
begin
MIMEMap := TIdMimeTable.Create(True);
try
Result := MIMEMap.GetFileMIMEType(AFile);
finally
MIMEMap.Free;
end;
end;