0
votes

I am generating emails with attachments thru a Delphi program using Indy 10 and TIdAttachment. The file location/name is stored in a database table as //server/files/attachments/MyAttachment.pdf. I am attaching the file to the email as follows:

   // Add each attachment in Attachments
    for Attachment in Attachments do begin
      // Make sure file name exists before trying to add
     if FileExists(Attachment) then
       TIdAttachmentFile.Create(MessageParts, Attachment);
    end;

When I send the email the file attached is named

'__server_files_attachments_MyAttachment.pdf'.

Is there a way to remove the file path so the attachment appears as 'MyAttachment.pdf' when the recipient receives the email?

I tried using ExtractFileName() but no luck. I don't think it works as the path & file name are coming from the database as one string.

EDIT

I also tried to extract the file name itself as follows:

function GetFileName(FullPath: string): string;
var
   StrFound: TStringList;
begin
    StrFound := TStringList.Create();
    ExtractStrings(['/'], [' '], PChar(FullPath), StrFound);
    result := StrFound[StrFound.Count - 1];
end;

This returns 'MyAttachment.pdf' but this results in Delphi looking in the folder in which the program is running for the file not in '//server/files/attachments'. It appears that unless I can rename the attachment after calling TIdAttachmentFile.Create() I cannot change the file name.

EDIT - SOLUTION

Showing the solution using Remy's comments (and using GetFileName() from above):

// Add each attachment in Attachments
for Attachment in Attachments do begin
  // Make sure file name exists before trying to add
  if FileExists(Attachment) then begin
     with TIdAttachmentFile.Create(MessageParts, Attachment) do begin
       Filename := GetFileName(Attachment);
     end;
  end;
end;
3
Exactly what did you pass to ExtractFileName?David Heffernan
I called ExtractFileName(attachment); where 'attachment' is '//server/files/attachments/MyAttachment.pdf'BrianKE
It's better if you post the solution at the bottom of Remy's accepted answer. Question is just for... question. Feel free to edit someone else posts, SO is a place to share knowledge ;)bluish

3 Answers

2
votes

Windows may recognize '/' as a path delimiter, but the RTL does not. Local paths and UNC paths alike must use '\' instead. You will have to normalize your filename string from '/' to '\' before passing it to Indy, such as with UnixPathToDosPath().

2
votes

You can create the TIdAttachmentFile with only the filename you want the attachment to have. After construction, set the StoredPathName property of the attachment to the full path.

var
  a: TIdAttachmentFile;
  FileName: string;

...

  FileName := ExtractFilePath(AttachmentPath);
  a := TIdAttachmentFile.Create(MessageParts, FileName);
  a.StoredPathName := AttachmentPath;
0
votes

The call to TIdAttachment.Create includes its own ExtractFilename call, so you don't need to call it ahead of time - it needs that path to find your files.

I think you're in a catch-22, you need to send the TidAttachment.Create a path that it understands because it uses the full path to add your file, then it extracts just the filename for you as you want to include in your message. I don't think it's working like you want because it can't perform the ExtractFilename part appropriately. So, rather than extract the filename, just form the path in a way the the TIdAttachment.Create can understand.

In this case, I'd try mapping a drive, and use the drive mapping as:

Z:\files\attachments\MyAttachment.pdf = //server/files/attachments/MyAttachment.pdf

Just pre-process your attachments replacing //server with Z:\ and / with \ then try it.

Edited to consider Remy's comment: Swap / chars to \ chars

\\server\files\attachments\myattachment.pdf

Then make the call to TIdAttachment.Create