How do I include a file in a TIdMultiPartFormDataStream for use with Indy IdHTTP1.Post?

允我心安 提交于 2019-11-29 15:30:47

I see a few problems with your code.

You are erroneously escaping \ characters in your file paths. That is necessary in languages like C and C++, but is not needed in Delphi at all, so get rid of it.

Change this:

Afilename := 'C:\\Users\\Admin\\Documents\\arrival and departure small.pdf';

To this:

Afilename := 'C:\Users\Admin\Documents\arrival and departure small.pdf';

The next problem I see is you are not naming the file attachment fields correctly when adding them to the TIdMultipartFormDataStream.

When calling AddFile(), you are passing the complete file path as-is to the AFieldName parameter, instead of using names like file0, file1, etc like shown in Elastic's examples.

Change this:

FormData.Addfile(filenames[i], filenames[i],MIMEStr);

To this 1:

FormData.AddFile('file'+IntToStr(i), filenames[i], MIMEStr);

1: FYI, there is no need to call GetMIMETypeForFile() manually, AddFile() calls GetMIMETypeForFile() internally for you if you do not provide a string for the AContentType parameter, eg FormData.AddFile('file'+IntToStr(i), filenames[i]);

You made a similar mistake when you tried to use AddFormField() instead of AddFile() to add attachments. You used each file's actual data content for the AFieldName parameter, instead of using the content for the AFieldValue parameter.

In that case, change this:

FormData.AddFormField(AttachmentContent.ToString,filenames[i]);

To this:

FormData.AddFormField('file'+IntToStr(i), AttachmentContent.ToString, '', MIMEStr, filenames[i]);

Or, since you were opening TFileStream objects yourself, you could use the overloaded AddFormField() method that takes a TStream as input (just be sure NOT to free the TStream objects until after you are done using the TIdMultipartFormDataStream!):

AttachmentContent := TFileStream.Create(filenames[i], fmOpenRead);
FormData.AddFormField('file'+IntToStr(i), MIMEStr, '', AttachmentContent, filenames[i]);

With that said, try something more like this:

function TForm1.Upload(url: string; params, filenames: TStrings): string;
var
 FormData : TIdMultiPartFormDataStream;
 ResponseText : string;
 i : integer;
begin
  FormData := TIdMultiPartFormDataStream.Create;
  try
    for i := 0 to params.Count - 1 do
      FormData.AddFormField(params.Names[i], params.ValueFromIndex[i]);

    for i := 0 to filenames.Count - 1 do
      FormData.AddFile('file'+IntToStr(i), filenames[i]);

    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;
  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 := TStringList.Create;
    try
      Filenames.Add(Afilename);

      url := ELASTIC_EMAIL_EMAIL_SEND;
      Upload(url, params, filenames);
    finally
      Filenames.Free;
    end;
  finally
    Params.Free;
  end;
end;

Lastly, Elastic's documentation does not say anything about the encoding needed for filenames that contain non-ASCII/reserved characters in it. And there are conflicting standards as to how such filenames should be encoded when transmitted over HTTP. By default, TIdMultipartFormDataStream encodes filenames according to RFC 2047. If that turns out to be a problem for Elastic to handle (your example filename has space characters in it, I forget whether TIdMultipartFormDataStream RFC-encodes a filename due to spaces or not, hopefully not), you can disable TIdMultipartFormDataStream's default encoding by setting an affected file's TIdFormDataField.HeaderEncoding property to '8' (for 8-bit) and then you can set the TIdFormDataField.FileName property to whatever encoding you want:

with FormData.AddFile('file'+IntToStr(i), filenames[i]) do
begin
  HeaderEncoding := '8';
  FileName := EncodeFilenameMyWay(ExtractFileName(filenames[i]));
end;
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!