The outlook send dialog doesn't show - delphi

I have a delphi 6 application wich uses mapi to open the outlook send dialog
with attachment.
This works on my PC and also on other clients PC.
I have now 2 clients where the send dialog isn't opening. I don't even get a
Error message. The clients have a W7 PC and outlook 2013.
I've tried Fixmapi, but this doesn't help.
Outlook is working fine and Via explorer the send dialogue is working fine.

I just tried MAPI and it worked for me, with thunderbird, and outlook 2013.
I did get a FIXMAPI dialog and then I got the new outlook email window, same as ever.
If you have a problem only on specific machines, then that's not a programming question, it's a windows question. Be sure to use the Control Panel to look at what default programs you have selected, including which is the default MAPI mail program.
program MapiSample;
uses
{Vcl.}Forms,
Windows,
SysUtils,
{Vcl.}Dialogs,
{WinApi.}MAPI;
type
LPSTR = PAnsiChar;
PSTR = PChar;
function SendMailMAPI(const Subject, Body, FileName, SenderName, SenderEMail,
RecepientName, RecepientEMail: AnsiString) : Integer;
var
message: TMapiMessage;
lpSender,
lpRecepient: TMapiRecipDesc;
FileAttach: TMapiFileDesc;
SM: TFNMapiSendMail;
MAPIModule: HModule;
begin
FillChar(message, SizeOf(message), 0);
with message do
begin
if (Subject<>'') then
begin
lpszSubject := LPSTR(Subject)
end;
if (Body<>'') then
begin
lpszNoteText := LPSTR(Body)
end;
if (SenderEMail<>'') then
begin
lpSender.ulRecipClass := MAPI_ORIG;
if (SenderName='') then
begin
lpSender.lpszName := LPSTR(SenderEMail)
end
else
begin
lpSender.lpszName := LPSTR(SenderName)
end;
lpSender.lpszAddress := LPSTR('SMTP:'+SenderEMail);
lpSender.ulReserved := 0;
lpSender.ulEIDSize := 0;
lpSender.lpEntryID := nil;
lpOriginator := #lpSender;
end;
if (RecepientEMail<>'') then
begin
lpRecepient.ulRecipClass := MAPI_TO;
if (RecepientName='') then
begin
lpRecepient.lpszName := LPSTR(RecepientEMail)
end
else
begin
lpRecepient.lpszName := LPSTR(RecepientName)
end;
lpRecepient.lpszAddress := LPSTR('SMTP:'+RecepientEMail);
lpRecepient.ulReserved := 0;
lpRecepient.ulEIDSize := 0;
lpRecepient.lpEntryID := nil;
nRecipCount := 1;
lpRecips := #lpRecepient;
end
else
begin
lpRecips := nil
end;
if (FileName='') then
begin
nFileCount := 0;
lpFiles := nil;
end
else
begin
FillChar(FileAttach, SizeOf(FileAttach), 0);
FileAttach.nPosition := Cardinal($FFFFFFFF);
FileAttach.lpszPathName := LPSTR(FileName);
nFileCount := 1;
lpFiles := #FileAttach;
end;
end;
MAPIModule := LoadLibrary(PSTR(MAPIDLL));
if MAPIModule=0 then
begin
Result := -1
end
else
begin
try
#SM := GetProcAddress(MAPIModule, 'MAPISendMail');
if #SM<>nil then
begin
Result := SM(0, Application.Handle, message, MAPI_DIALOG or
MAPI_LOGON_UI, 0);
end
else
begin
Result := 1
end;
finally
FreeLibrary(MAPIModule);
end;
end;
if Result<>0 then
begin
MessageDlg('Error sending mail ('+IntToStr(Result)+').', mtError, [mbOk],
0)
end;
end;
begin
SendMailMapi('test','test','','My Name', 'sender#sender.com', 'Your Name', 'receiver#something.com');
end.

Related

Can TNEF be avoided using MAPI?

I am using this code to send emails through MAPI using Delphi.
A few users who use Microsoft mailing software report that the receipants receive emails with an attachment WinMail.dat. I know that this is an issue with Microsoft Exchange/Outlook and can be corrected by disabling RTF/TNEF. (I don't know for sure because I do not use Microsoft mailing software).
My question is, if I can tell the mailing software to not use TNEF using the MAPI.
function SendEMailUsingMAPI(const Subject, Body, FileName, SenderName, SenderEMail, RecipientName, RecipientEMail: string): Integer;
var
Message: TMapiMessage;
lpSender, lpRecipient: TMapiRecipDesc;
FileAttach: TMapiFileDesc;
SM: TFNMapiSendMail;
MAPIModule: HModule;
FileType: TMapiFileTagExt;
begin
// Source: http://www.stackoverflow.com/questions/1234623/how-to-send-a-mapi-email-with-an-attachment-to-a-fax-recipient
// Modified
FillChar(Message,SizeOf(Message),0);
if (Subject <> '') then begin
Message.lpszSubject := PChar(Subject);
end;
if (Body <> '') then begin
Message.lpszNoteText := PChar(Body);
end;
if (SenderEmail <> '') then
begin
lpSender.ulRecipClass := MAPI_ORIG;
if (SenderName = '') then begin
lpSender.lpszName := PChar(SenderEMail);
end
else begin
lpSender.lpszName := PChar(SenderName);
end;
lpSender.lpszAddress := PChar('smtp:'+SenderEmail);
lpSender.ulReserved := 0;
lpSender.ulEIDSize := 0;
lpSender.lpEntryID := nil;
Message.lpOriginator := #lpSender;
end;
if (RecipientEmail <> '') then
begin
lpRecipient.ulRecipClass := MAPI_TO;
if (RecipientName = '') then begin
lpRecipient.lpszName := PChar(RecipientEMail);
end
else begin
lpRecipient.lpszName := PChar(RecipientName);
end;
lpRecipient.lpszAddress := PChar('smtp:'+RecipientEmail);
lpRecipient.ulReserved := 0;
lpRecipient.ulEIDSize := 0;
lpRecipient.lpEntryID := nil;
Message.nRecipCount := 1;
Message.lpRecips := #lpRecipient;
end
else begin
Message.lpRecips := nil;
end;
if (FileName = '') then begin
Message.nFileCount := 0;
Message.lpFiles := nil;
end
else begin
FillChar(FileAttach,SizeOf(FileAttach),0);
FileAttach.nPosition := Cardinal($FFFFFFFF);
FileAttach.lpszPathName := PChar(FileName);
FileType.ulReserved := 0;
FileType.cbEncoding := 0;
FileType.cbTag := 0;
FileType.lpTag := nil;
FileType.lpEncoding := nil;
FileAttach.lpFileType := #FileType;
Message.nFileCount := 1;
Message.lpFiles := #FileAttach;
end;
MAPIModule := LoadLibrary(PChar(MAPIDLL));
if MAPIModule = 0 then begin
Result := -1;
end
else begin
try
#SM := GetProcAddress(MAPIModule,'MAPISendMail');
if #SM <> nil then begin
Result := SM(0,Application.Handle,Message,
MAPI_DIALOG or MAPI_LOGON_UI,0);
end
else begin
Result := 1;
end;
finally
FreeLibrary(MAPIModule);
end;
end;
if Result <> 0 then begin
raise Exception.CreateFmt('Error sending eMail (%d)', [Result]);
end;
end;
Not in Simple MAPI. If you were using Outlook Object Model or Extended MAPI, you could set a special MAPI property on the message before sending it to disable TNEF format.

Sending a File via a secure connection with Indy to a website

I have to send an XML-File to a Website with a secure Connection. Delphi 2010, Indy 10.5.9. The Code used is as follows:
Params: TIdMultiPartFormDataStream;
ResponseStr: string;
begin
result := 0;
sRootCertFile := 'xxx\Digital.pem';
sCertFile := 'xxx\Digital.pem';
sKeyFile := 'xxx\Digital.pem';
with FAdminSetup.RDWSSLHandler do
begin
SSLOptions.VerifyMode := [];
SSLOptions.VerifyDepth := 0;
SSLOptions.RootCertFile := sRootCertFile;
SSLOptions.CertFile := sCertFile;
SSLOptions.KeyFile := sKeyFile;
end;
sURL := 'https://xxx/xxxservice';
begin
IdHttpVVO := TIdHttp.Create(nil);
try
// IdHttpVVO.Request.ContentType := 'multipart/form-data';
// IdHttpVVO.ProtocolVersion := pv1_1;
// IdHttpVVO.HTTPOptions := [hoKeepOrigProtocol,hoForceEncodeParams];
// IdHttpVVO.Request.Connection := 'Keep-Alive';
// IdHttpVVO.Request.CacheControl := 'no-cache';
// IdHttpVVO.Request.ContentLength := Length(sAnsiXML); // <-- new
IdHttpVVO.IOHandler := FAdminSetup.RDWSSLHandler;
Params := TIdMultiPartFormDataStream.Create;
try
with Params do
begin
AddFile('file', filename, GetMIMETypeFromFile(filename));
end;
resultStr := IdHttpVVO.Post(sURL, Params);
finally
Params.Free;
end;
ShowMessage(resultstr);
The result is always the same:
'HTTP/1.0 500 Error'
when doing the post part.
All the remarks have been tried and did not give any change. The Password for the connection is supplied as follows:
procedure TFAdminSetup.RDWSSLHandlerGetPasswordEx(ASender: TObject;
var VPassword: AnsiString; const AIsWrite: Boolean);
begin
VPassword := 'xxx';
end;
The Website is working, the certificates seem to be ok, as there is a small tool included written in C that works.
Where is my mistake? Thanks

Retrieving filename from IDataObject in Delphi

I'm building a Delphi XE3 application which needs to be able to have files dropped onto it. I have the Explorer > Application side of things working, but for the life of me can't figure out to get the filename when going from Application > Application.
Assuming one file is dropped from say Outlook (or any other application), I have this which works as long as I manually assign filename before hand.
SetFormatEtc( FormatEtc , CF_FILECONTENTS );
OleCheck( dataObj.GetData( FormatEtc , Medium ) );
OleStream := TOleStream.Create( IUnknown( Medium.stm ) as IStream );
MemStream := TMemoryStream.Create;
OleStream.Position := 0;
MemStream.CopyFrom( OleStream , OleStream.Size );
TMemoryStream( MemStream ).SaveToFile( 'C:\' + filename );
MemStream.Free;
OleStream.Free;
ReleaseStgMedium( Medium );
CF_FILECONTENTS format can contain several stream. You must check CF_FILEDESCRIPTORW and CF_FILEDESCRIPTORA formats for detection of stream count and stream names. Some sources:
function ContainFormat(ADataObject: IDataObject; AFormat: TClipFormat;
ATymed: Longint; AAspect: LongInt = DVASPECT_CONTENT; AIndex: LongInt = -1): Boolean;
var Format: TFormatEtc;
begin
ZeroMemory(#Format, SizeOf(Format));
Format.cfFormat := AFormat;
Format.dwAspect := AAspect;
Format.lindex := AIndex;
Format.tymed := ATymed;
Result := ADataObject.QueryGetData(Format) = S_OK;
end;
procedure InvalidMedium;
begin
raise Exception.Create('Invalid medium');
end;
function ExtractStream(ADataObject: IDataObject; AIndex: Integer): IStream;
var Format: TFormatEtc;
Medium: TStgMedium;
begin
ZeroMemory(#Format, SizeOf(Format));
Format.cfFormat := CF_FILECONTENTS;
Format.dwAspect := DVASPECT_CONTENT;
Format.lindex := AIndex;
Format.tymed := TYMED_ISTREAM;
ZeroMemory(#Medium, SizeOf(Medium));
OleCheck(ADataObject.GetData(Format, Medium));
try
if (Medium.tymed and TYMED_ISTREAM = 0) or not Assigned(Medium.stm) then
InvalidMedium;
Result := IStream(Medium.stm);
finally
ReleaseStgMedium(Medium);
end
end;
procedure WorkWithDropObject(const AFileName: UnicodeString; AStream: IStream);
begin
end;
procedure ProcessDataObject(ADataObject: IDataObject);
var Format: TFormatEtc;
Medium: TStgMedium;
FGDA: PFileGroupDescriptorA;
FGDW: PFileGroupDescriptorW;
i: Integer;
Stream: IStream;
begin
if ContainFormat(ADataObject, CF_FILECONTENTS, TYMED_ISTREAM) then
begin
if ContainFormat(ADataObject, CF_FILEDESCRIPTORW, TYMED_HGLOBAL) then
begin
Format.cfFormat := CF_FILEDESCRIPTORW;
Format.dwAspect := DVASPECT_CONTENT;
Format.lindex := -1;
Format.tymed := TYMED_HGLOBAL;
ZeroMemory(#Medium, SizeOf(Medium));
OleCheck(ADataObject.GetData(Format, Medium));
try
if (Medium.tymed and TYMED_HGLOBAL = 0) or (Medium.hGlobal = 0) then
InvalidMedium;
FGDW := GlobalLock(Medium.hGlobal);
if not Assigned(FGDW) then
RaiseLastOSError;
try
for i := 0 to FGDW.cItems - 1 do
begin
Stream := ExtractStream(ADataObject, i);
try
WorkWithDropObject(FGDW.fgd[i].cFileName, Stream);
finally
Stream := nil;
end;
end;
finally
GlobalUnlock(Medium.hGlobal);
end;
finally
ReleaseStgMedium(Medium);
end
end
else
if ContainFormat(ADataObject, CF_FILEDESCRIPTORA, TYMED_HGLOBAL) then
begin
Format.cfFormat := CF_FILEDESCRIPTORA;
Format.dwAspect := DVASPECT_CONTENT;
Format.lindex := -1;
Format.tymed := TYMED_HGLOBAL;
ZeroMemory(#Medium, SizeOf(Medium));
OleCheck(ADataObject.GetData(Format, Medium));
try
if (Medium.tymed and TYMED_HGLOBAL = 0) or (Medium.hGlobal = 0) then
InvalidMedium;
FGDA := GlobalLock(Medium.hGlobal);
if not Assigned(FGDA) then
RaiseLastOSError;
try
for i := 0 to FGDA.cItems - 1 do
begin
Stream := ExtractStream(ADataObject, i);
try
WorkWithDropObject(FGDA.fgd[i].cFileName, Stream);
finally
Stream := nil;
end;
end;
finally
GlobalUnlock(Medium.hGlobal);
end;
finally
ReleaseStgMedium(Medium);
end
end;
end;
end;
Also I you want to create universal software you should process the following formats:
CF_FILENAMEW/CF_FILENAMEA
CF_HDROP
CF_IDLIST
CF_FILEDESCRIPTORW/CF_FILEDESCRIPTORA/CF_FILECONTENTS

Why does SendMailMAPI rename file attachments to shorter ones?

I use the following emailing function with Eudora. For some reason the attachment file name is renamed to be something else. How can I make sure the attachment file name remains intact?
function SendMailMAPI(const Subject, Body, FileName, SenderName, SenderEMail,
RecepientName, RecepientEMail: String) : Integer;
var
message: TMapiMessage;
lpSender,
lpRecepient: TMapiRecipDesc;
FileAttach: TMapiFileDesc;
SM: TFNMapiSendMail;
MAPIModule: HModule;
begin
FillChar(message, SizeOf(message), 0);
with message do
begin
if (Subject<>'') then
begin
lpszSubject := PChar(Subject)
end;
if (Body<>'') then
begin
lpszNoteText := PChar(Body)
end;
if (SenderEMail<>'') then
begin
lpSender.ulRecipClass := MAPI_ORIG;
if (SenderName='') then
begin
lpSender.lpszName := PChar(SenderEMail)
end
else
begin
lpSender.lpszName := PChar(SenderName)
end;
lpSender.lpszAddress := PChar('SMTP:'+SenderEMail);
lpSender.ulReserved := 0;
lpSender.ulEIDSize := 0;
lpSender.lpEntryID := nil;
lpOriginator := #lpSender;
end;
if (RecepientEMail<>'') then
begin
lpRecepient.ulRecipClass := MAPI_TO;
if (RecepientName='') then
begin
lpRecepient.lpszName := PChar(RecepientEMail)
end
else
begin
lpRecepient.lpszName := PChar(RecepientName)
end;
lpRecepient.lpszAddress := PChar('SMTP:'+RecepientEMail);
lpRecepient.ulReserved := 0;
lpRecepient.ulEIDSize := 0;
lpRecepient.lpEntryID := nil;
nRecipCount := 1;
lpRecips := #lpRecepient;
end
else
begin
lpRecips := nil
end;
if (FileName='') then
begin
nFileCount := 0;
lpFiles := nil;
end
else
begin
FillChar(FileAttach, SizeOf(FileAttach), 0);
FileAttach.nPosition := Cardinal($FFFFFFFF);
FileAttach.lpszPathName := PChar(FileName);
nFileCount := 1;
lpFiles := #FileAttach;
end;
end;
MAPIModule := LoadLibrary(PChar(MAPIDLL));
if MAPIModule=0 then
begin
Result := -1
end
else
begin
try
#SM := GetProcAddress(MAPIModule, 'MAPISendMail');
if #SM<>nil then
begin
Result := SM(0, Application.Handle, message, MAPI_DIALOG or
MAPI_LOGON_UI, 0);
end
else
begin
Result := 1
end;
finally
FreeLibrary(MAPIModule);
end;
end;
if Result<>0 then
begin
MessageDlg('Error sending mail ('+IntToStr(Result)+').', mtError, [mbOk],
0)
end;
You have to set FileAttach.lpszFileName to the name you want your recipient to see. If you don't do that an attachment like "C:\Document And Settings\MyUser\Local Settings\Temp\Hello.pdf" will look like "C__DOCUME~1_MyUser_LOCALS~1_Temp_Hello.pdf" to the recipient (this is probably different per e-mailclient ).
So set FileAttach.lpszPathName to contain only the filename:
begin
FillChar(FileAttach, SizeOf(FileAttach), 0);
FileAttach.nPosition := Cardinal($FFFFFFFF);
FileAttach.lpszPathName := PChar(FileName);
FileAttach.lpszFileName := PChar(ExtractFileName(FileName)); //add this
nFileCount := 1;
lpFiles := #FileAttach;
end;
The recipient will now see an attachment with the name "Hello.pdf" instead of "C__DOCUME~1_MyUser_LOCALS~1_Temp_Hello.pdf".

Outlook IPreviewHandler for Delphi

I have been able to implement a preview handler for most file types, except outlook msg files. How can I achieve this? The code doesnt seem to be able to open either in stream or file mode.
var
ACLSID: String;
AGUID: TGUID;
ARect: TRect;
FileInit: IInitializeWithFile;
StreamInit : IInitializeWithStream;
begin
FPreviewHandler := CreateComObject(AGUID) as IPreviewHandler;
if (FPreviewHandler = nil) then
begin
MessageDlg('No preview handler found for this file format.', mtError, [mbOK], 0);
Result := False;
Exit;
end;
// First attempt opening in file mode, if fails, attempt stream mode.
if FPreviewHandler.QueryInterface(IInitializeWithFile, FileInit) = 0 then
begin
FileInit.Initialize(StringToOleStr(FFileName), STGM_READ);
FInStreamMode := False;
FLoaded := True;
end else
if FPreviewHandler.QueryInterface(IInitializeWithStream, StreamInit) = 0 then
begin
try
FFileStream := TFileStream.Create(FFileName, fmOpenRead);
except on
E: EFOpenError do
begin
MessageDlg(E.Message, mtError, [mbOK], 0);
Result := False;
Exit;
end;
end;
FIStream := TStreamAdapter.Create(FFileStream, soOwned) as IStream;
StreamInit.Initialize(FIStream, STGM_READ);
FInStreamMode := True;
FLoaded := True;
end else
begin // Cannot load file
Result := False;
FPreviewHandler.Unload;
Exit;
end;
ARect := Rect(0, 0, AParentControl.Width, AParentControl.Height);
Parent := AParentControl;
Align := alClient;
FPreviewHandler.SetWindow(Self.Handle, ARect);
FPreviewHandler.SetRect(ARect);
FPreviewHandler.DoPreview;
FPreviewHandler.SetFocus;

Resources