私のプログラムでは、ユーザーのマシンにインストールされているデフォルトの電子メールクライアントソフトウェアを使用して送信する電子メールを作成しています。
Mailtoアドレス、件名、複数行の本文を作成しました。いくつかの添付ファイルを含める必要があります。
次のように、mailtoとShellExecuteを使用してこれをほぼ機能させました。
Message := 'mailto:[email protected]'
+ '?subject=This is the subjectBehold Error Report'
+ '&body=This is line 1' + '%0D%0A'
+ 'This is line 2' + '%0D%0A'
+ 'This is line 3'
+ '&Attach=c:\file1.txt';
RetVal := ShellExecute(Handle, 'open', PChar(Message), nil, nil, SW_SHOWNORMAL);
if RetVal <= 32 then
MessageDlg('Cannot find program to send e-mail.', mtWarning, [mbOK], 0);
WindowsVistaマシンでDelphi2009を使用すると、宛先、件名、本文が正しく入力されたMicrosoftMailの[メールの作成]ウィンドウが開きます。ただし、ファイルは添付されません。
これを調べていると、この手法がすべてのメールクライアントで機能するとは限らないというコメントに気づきました。ただし、これは非常に古い手法であることがわかっているため、ほとんどの解説はかなり古いものです。
次に、 Zarko Gajicが言った 「このアプローチは問題ありませんが、この方法で添付ファイルを送信することはできません」ということがわかりました。
Windows Simple Mail API(MAPI)も見たことがありますが、Zarkoは、エンドユーザーがMAPI準拠の電子メールソフトウェアを使用している場合にのみ機能すると述べています。 DelphiでMAPIを使用する方法については十分に文書化されています(例: mapiを使用して電子メールを送信する )が、MAPIが常にWindowsにインストールされるとは限らないという免責事項があります。
さらに、ユーザーのデフォルトの電子メールプログラムで最初にメッセージが表示されるようにしたいので、ユーザーはメッセージを電子メールレコードの一部として保持し、編集して送信するかどうか、いつ送信するかを決定できます。 MAPIがどのように機能するのか、そしてそれが機能するかどうかはわかりません。
したがって、私の要件は次のとおりです。
ユーザーのメールプログラムでメールを表示します。
1つ以上の添付ファイルを許可します。
XPから(つまり、XP、Vista、または7)までの任意のWindowsマシン上のすべての電子メールクライアントを(うまくいけば)操作するため。
そのような動物はいますか?あるいは、誰かが添付ファイルをmailto/ShellExecuteテクニックで動作させる方法を知っていますか?
ほとんどの人は何をしますか?
編集:
MAPIソリューションやIndyソリューションでさえいくつかの答えがありました。
私が彼らに抱えている問題は、彼らが必ずしもデフォルトのメールクライアントを使用しているとは限らないということです。たとえば、Vistaマシンでは、デフォルトのクライアントとしてWindowsメールを設定しました。 MAPI送信を実行すると、Windowsメールは表示されませんが、代わりにOutlookでメールが表示されて設定されます。私はそれを望んでいません。
私のプログラムの2人のユーザーが不満を言った:
デバッグルーチンは、デフォルトのメールクライアント(私の場合はThunderbird)を使用するのではなく、何らかの理由でWindowsメールを開始しようとするため、ファイルの送信に失敗します。
例外レポートを埋めようとしましたが、このサーバー、そのサーバーを要求されたときに諦めました!その後、Outlookが起動したので、本当にイライラしました。これを使用したり、使用したりすることはありません。
MAPIやIndyのコードは必要ありません。それらはすぐに利用できます。しかし、MAPIまたはIndyを提案する場合、私が本当に必要としているのは、デフォルトのクライアントを見つけて、送信される電子メールが渡されるクライアントであることを確認する方法です。
また、MAPIがユニバーサルになったかどうかを知る必要があります。 5年前は、オペレーティングシステムの一部としてインストールされていなかったため、すべてのマシンで動作することが保証されていませんでした。それはまだ本当ですか、それともMAPIはWindows XP、Vista、7にデフォルトで付属していますか?
Indyやその他の提案された解決策についても同じ質問があります。デフォルトのクライアントで動作し、ほぼすべてのWindows XP以降のマシンで動作しますか?
「mailto」ソリューションが非常に優れている理由は、すべてのマシンがWebページにあるHTMLmailtoステートメントを処理するためにそれをサポートする必要があるためです。今、私がそれを使用して添付ファイルを追加できれば...
考えられる解決策が見つかりました:mjustinは、オペレーティングシステムのsendtoコマンドを利用する代替手段を指摘しました。それはおそらく行く方法です。
MailtoはHTMLのmailtoのように256文字に制限されていませんでしたが、最終的に2048文字に制限されていることに気づきました。幸いなことに、数時間後、マジャスティンは彼の答えを出しました。
それの実装がうまくいけば、彼の答えは私のためにそれをしたでしょう。そうでない場合は、ここにコメントを追加します。
いいえ。結局のところ、sendtoソリューションは常にデフォルトの電子メールプログラムを開くとは限りません。私のマシンでは、デフォルトのメーラーがWindowsメールの場合にOutlookが開きます。残念な。 2048文字の制限にもかかわらず、mailtoメソッドに戻らなければなりませんでした。
しかし、私は記事で見つけました: SendToメール受信者 それ:
この時点で、レジストリで宣言されている実際のmailtoコマンドラインを使用して:: ShellExecuteをよく考えられた:: WinExec呼び出しに置き換え、現在の電子メールクライアント(たとえば、 "%ProgramFiles%\ Outlook Express\msimn .exe "/ mailurl:%1)。ただし、制限は32KBです。結論として、mailtoプロトコルを使用して32KBを超える電子メールを送信する方法はありません。
しかし、その場合、メールクライアントが誰であるかを判断する必要があります。それはさらなる合併症につながると思います。
私が見つけたもう1つのことは、mailtoでは「to」、「cc」、「bcc」、「subject」、「body」の設定は許可されていますが、添付ファイルは許可されていないことです。 sendtoは添付ファイルのみを許可し、デフォルトのメッセージを含むデフォルトの電子メールを設定しますが、さまざまなフィールドと本文を設定する方法はありません。
ShellExecuteのmailtoは添付ファイルを送信できないようです。
MAPIとIndyには、必ずしもユーザーの電子メールクライアントを選択するとは限らないという不幸な特徴があります。
したがって、他の可能性はShellExecuteを引き続き使用することですが、添付ファイルを電子メールクライアントに取り込む別の方法を見つけます。
私がやろうと決めたのは、電子メールを作成するダイアログで、ユーザーが電子メールに添付する可能性のあるファイルを一覧表示するFileListBoxができました。メールがポップアップしたら、メールにドラッグアンドドロップするだけです。
私の場合、これは実際には良い解決策です。これにより、ユーザーは含めるファイルを選択できるようになります。もう1つの方法(自動的にアタッチする)では、含めたくないものを削除する必要があります。 (つまり、[Googleツールバーを追加]オプションが既にオンになっているのは良くありません)
当面、このソリューションは機能します。
回答を提供し、これを通り抜けるのを手伝ってくれたすべての人に感謝します(すべて+1)。
複雑にしないでください。 [〜#〜] jcl [〜#〜] MAPIコードを使用してください。ユニットJclMapi.pasにあります。彼らにもその例があると思います。コードは非常に強力で、MAPIで可能なことは何でもできます。
ShellExecuteを使用すると、添付ファイルを送信できず、メール本文も255文字に制限されます。
MAPIが機能する限り、古いウィンドウでは常にインストールされます(2000、XP)。 Outlook Expressに付属しており、ほとんどの場合OutlookExpressがインストールされます。新しいウィンドウ(Vista、7)では、Outlook Expressがないため、MAPIはありません。ただし、MSOutlookまたはMozzilaThunderbirdをインストールすると、MAPIが自動的にインストールされます。だからあなたはかなり安全です。これは基本的なMAPIであり、拡張MAPIではありません。しかし、それはあなたが必要とするすべてをカバーします。
MAPIがインストールされているかどうかをコード(JCL)でチェックインし、それに応じて動作することもできます。私はそれほど前に同様のことをしました、そしてそれは大丈夫です。単純なMAPIをサポートしていない人気のあるWindowsメールクライアントは見つかりませんでした。これは、JCLコードと以下のサンプル使用法の単純なラッパーです。
unit MAPI.SendMail;
interface
uses
SysUtils, Classes, JclMapi;
type
TPrerequisites = class
public
function IsMapiAvailable: Boolean;
function IsClientAvailable: Boolean;
end;
TMAPISendMail = class
private
FAJclEmail: TJclEmail;
FShowDialog: Boolean;
FResolveNames: Boolean;
FPrerequisites: TPrerequisites;
// proxy property getters
function GetMailBody: string;
function GetHTMLBody: Boolean;
function GetMailSubject: string;
// proxy property setters
procedure SetMailBody(const Value: string);
procedure SetHTMLBody(const Value: Boolean);
procedure SetMailSubject(const Value: string);
protected
function DoSendMail: Boolean; virtual;
public
constructor Create;
destructor Destroy; override;
// properties of the wrapper class
property MailBody: string read GetMailBody write SetMailBody;
property HTMLBody: Boolean read GetHTMLBody write SetHTMLBody;
property ShowDialog: Boolean read FShowDialog write FShowDialog;
property MailSubject: string read GetMailSubject write SetMailSubject;
property ResolveNames: Boolean read FResolveNames write FResolveNames;
property Prerequisites: TPrerequisites read FPrerequisites;
// procedure and functions of the wrapper class
procedure AddRecipient(const Address: string; const Name: string = '');
procedure AddAttachment(const FileName: string);
function SendMail: Boolean;
end;
implementation
{ TMAPISendMail }
constructor TMAPISendMail.Create;
begin
FPrerequisites := TPrerequisites.Create;
FAJclEmail := TJclEmail.Create;
FShowDialog := True;
end;
destructor TMAPISendMail.Destroy;
begin
FreeAndNil(FAJclEmail);
FreeAndNil(FPrerequisites);
inherited;
end;
function TMAPISendMail.DoSendMail: Boolean;
begin
Result := FAJclEmail.Send(FShowDialog);
end;
function TMAPISendMail.SendMail: Boolean;
begin
Result := DoSendMail;
end;
function TMAPISendMail.GetMailBody: string;
begin
Result := FAJclEmail.Body;
end;
procedure TMAPISendMail.SetMailBody(const Value: string);
begin
FAJclEmail.Body := Value;
end;
procedure TMAPISendMail.AddAttachment(const FileName: string);
begin
FAJclEmail.Attachments.Add(FileName);
end;
procedure TMAPISendMail.AddRecipient(const Address, Name: string);
var
LocalName: string;
LocalAddress: string;
begin
LocalAddress := Address;
LocalName := Name;
if FResolveNames then
if not FAJclEmail.ResolveName(LocalName, LocalAddress) then
raise Exception.Create('Could not resolve Recipient name and address!');
FAJclEmail.Recipients.Add(LocalAddress, LocalName);
end;
function TMAPISendMail.GetMailSubject: string;
begin
Result := FAJclEmail.Subject;
end;
procedure TMAPISendMail.SetMailSubject(const Value: string);
begin
FAJclEmail.Subject := Value;
end;
function TMAPISendMail.GetHTMLBody: Boolean;
begin
Result := FAJclEmail.HtmlBody;
end;
procedure TMAPISendMail.SetHTMLBody(const Value: Boolean);
begin
FAJclEmail.HtmlBody := Value;
end;
{ TPrerequisites }
function TPrerequisites.IsClientAvailable: Boolean;
var
SimpleMAPI: TJclSimpleMapi;
begin
SimpleMAPI := TJclSimpleMapi.Create;
try
Result := SimpleMAPI.AnyClientInstalled;
finally
SimpleMAPI.Free;
end;
end;
function TPrerequisites.IsMapiAvailable: Boolean;
var
SimpleMAPI: TJclSimpleMapi;
begin
SimpleMAPI := TJclSimpleMapi.Create;
try
Result := SimpleMAPI.SimpleMapiInstalled;
finally
SimpleMAPI.Free;
end;
end;
end.
使用例:
unit f_Main;
interface
uses
Windows, SysUtils, Classes, Controls, Forms, Graphics, StdCtrls, XPMan,
// project units
JclMapi, MAPI.SendMail, Dialogs;
type
TfMain = class(TForm)
XPManifest: TXPManifest;
gbMailProperties: TGroupBox;
eMailSubject: TEdit;
stMailSubject: TStaticText;
stMailBody: TStaticText;
mmMailBody: TMemo;
cbHTMLBody: TCheckBox;
gbAttachments: TGroupBox;
gbRecipients: TGroupBox;
btnSendMail: TButton;
lbRecipients: TListBox;
eRecipAddress: TEdit;
StaticText1: TStaticText;
eRecipName: TEdit;
btnAddRecipient: TButton;
stRecipName: TStaticText;
OpenDialog: TOpenDialog;
lbAttachments: TListBox;
btnAddAttachment: TButton;
stMAPILabel: TStaticText;
stClientLabel: TStaticText;
stMAPIValue: TStaticText;
stClientValue: TStaticText;
procedure btnSendMailClick(Sender: TObject);
procedure btnAddRecipientClick(Sender: TObject);
procedure btnAddAttachmentClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
fMain: TfMain;
implementation
{$R *.dfm}
procedure TfMain.btnSendMailClick(Sender: TObject);
var
I: Integer;
Name: string;
Address: string;
ItemStr: string;
Pos1, Pos2: Integer;
MAPISendMail: TMAPISendMail;
begin
MAPISendMail := TMAPISendMail.Create;
try
for I := 0 to lbRecipients.Items.Count - 1 do
begin
ItemStr := lbRecipients.Items[I];
Pos1 := Pos('[', ItemStr);
Pos2 := Pos(']', ItemStr);
Name := Trim(Copy(ItemStr, Pos1 + 1, Pos2 - Pos1 - 1));
Address := Trim(Copy(ItemStr, 1, Pos1 - 1));
MAPISendMail.AddRecipient(Address, Name);
end;
for I := 0 to lbAttachments.Items.Count - 1 do
MAPISendMail.AddAttachment(lbAttachments.Items[I]);
MAPISendMail.MailSubject := eMailSubject.Text;
MAPISendMail.HTMLBody := cbHTMLBody.Checked;
MAPISendMail.MailBody := mmMailBody.Text;
MAPISendMail.SendMail;
finally
MAPISendMail.Free;
end;
end;
procedure TfMain.btnAddRecipientClick(Sender: TObject);
begin
lbRecipients.Items.Add(Format('%s [%s]', [eRecipAddress.Text,
eRecipName.Text]));
end;
procedure TfMain.btnAddAttachmentClick(Sender: TObject);
begin
if OpenDialog.Execute then
lbAttachments.Items.Add(OpenDialog.FileName);
end;
procedure TfMain.FormCreate(Sender: TObject);
var
ValidHost: Boolean;
MAPISendMail: TMAPISendMail;
begin
MAPISendMail := TMAPISendMail.Create;
try
ValidHost := True;
if MAPISendMail.Prerequisites.IsMapiAvailable then
begin
stMAPIValue.Caption := 'Available';
stMAPIValue.Font.Color := clGreen;
end
else
begin
stMAPIValue.Caption := 'Unavailable';
stMAPIValue.Font.Color := clRed;
ValidHost := False;
end;
if MAPISendMail.Prerequisites.IsClientAvailable then
begin
stClientValue.Caption := 'Available';
stClientValue.Font.Color := clGreen;
end
else
begin
stClientValue.Caption := 'Unavailable';
stClientValue.Font.Color := clRed;
ValidHost := False;
end;
btnSendMail.Enabled := ValidHost;
finally
MAPISendMail.Free;
end;
end;
end.
添付ファイルが必要かどうかに応じて、MAPIメールの送信に2つの方法を使用します。アタッチメントのない単純なケースでは、次を使用します。
function SendShellEmail( ARecipientEmail, ASubject, ABody : string ) : boolean;
// Send an email to this recipient with a subject and a body
var
iResult : integer;
S : string;
begin
If Trim(ARecipientEmail) = '' then
ARecipientEmail := 'mail';
S := 'mailto:' + ARecipientEmail;
S := S + '?subject=' + ASubject;
If Trim(ABody) <> '' then
S := S + '&body=' + ABody;
iResult := ShellExecute( Application.Handle,'open', PChar(S), nil, nil, SW_SHOWNORMAL);
Result := iResult > 0;
end;
これは単純なシェル実行メソッドを使用するため、プログラムが電子メールを送信しても問題がないことをユーザーに確認させるための最新のアラート以外に、実際の問題は発生しないはずです。
アタッチメントには、BrianLongがDelphiMagazineから取得した次のコードを使用します。 MAPIクライアントを使用せずに指定されたSMTPサーバーを使用して電子メールを送信することも可能ですが、明示的にこれを望まないと思います。もしそうなら、私はこれのためのコードを提供することができます。
uses
SysUtils,
Windows,
Dialogs,
Forms,
MAPI;
procedure ArtMAPISendMail(
const Subject, MessageText, MailFromName, MailFromAddress,
MailToName, MailToAddress: String;
const AttachmentFileNames: array of String);
//Originally by Brian Long: The Delphi Magazine issue 60 - Delphi And Email
var
MAPIError: DWord;
MapiMessage: TMapiMessage;
Originator, Recipient: TMapiRecipDesc;
Files, FilesTmp: PMapiFileDesc;
FilesCount: Integer;
begin
FillChar(MapiMessage, Sizeof(TMapiMessage), 0);
MapiMessage.lpszSubject := PAnsiChar(AnsiString(Subject));
MapiMessage.lpszNoteText := PAnsiChar(AnsiString(MessageText));
FillChar(Originator, Sizeof(TMapiRecipDesc), 0);
Originator.lpszName := PAnsiChar(AnsiString(MailFromName));
Originator.lpszAddress := PAnsiChar(AnsiString(MailFromAddress));
// MapiMessage.lpOriginator := @Originator;
MapiMessage.lpOriginator := nil;
MapiMessage.nRecipCount := 1;
FillChar(Recipient, Sizeof(TMapiRecipDesc), 0);
Recipient.ulRecipClass := MAPI_TO;
Recipient.lpszName := PAnsiChar(AnsiString(MailToName));
Recipient.lpszAddress := PAnsiChar(AnsiString(MailToAddress));
MapiMessage.lpRecips := @Recipient;
MapiMessage.nFileCount := High(AttachmentFileNames) - Low(AttachmentFileNames) + 1;
Files := AllocMem(SizeOf(TMapiFileDesc) * MapiMessage.nFileCount);
MapiMessage.lpFiles := Files;
FilesTmp := Files;
for FilesCount := Low(AttachmentFileNames) to High(AttachmentFileNames) do
begin
FilesTmp.nPosition := $FFFFFFFF;
FilesTmp.lpszPathName := PAnsiChar(AnsiString(AttachmentFileNames[FilesCount]));
Inc(FilesTmp)
end;
try
MAPIError := MapiSendMail(
0,
Application.MainForm.Handle,
MapiMessage,
MAPI_LOGON_UI {or MAPI_NEW_SESSION},
0);
finally
FreeMem(Files)
end;
case MAPIError of
MAPI_E_AMBIGUOUS_RECIPIENT:
Showmessage('A recipient matched more than one of the recipient descriptor structures and MAPI_DIALOG was not set. No message was sent.');
MAPI_E_ATTACHMENT_NOT_FOUND:
Showmessage('The specified attachment was not found; no message was sent.');
MAPI_E_ATTACHMENT_OPEN_FAILURE:
Showmessage('The specified attachment could not be opened; no message was sent.');
MAPI_E_BAD_RECIPTYPE:
Showmessage('The type of a recipient was not MAPI_TO, MAPI_CC, or MAPI_BCC. No message was sent.');
MAPI_E_FAILURE:
Showmessage('One or more unspecified errors occurred; no message was sent.');
MAPI_E_INSUFFICIENT_MEMORY:
Showmessage('There was insufficient memory to proceed. No message was sent.');
MAPI_E_LOGIN_FAILURE:
Showmessage('There was no default logon, and the user failed to log on successfully when the logon dialog box was displayed. No message was sent.');
MAPI_E_TEXT_TOO_LARGE:
Showmessage('The text in the message was too large to sent; the message was not sent.');
MAPI_E_TOO_MANY_FILES:
Showmessage('There were too many file attachments; no message was sent.');
MAPI_E_TOO_MANY_RECIPIENTS:
Showmessage('There were too many recipients; no message was sent.');
MAPI_E_UNKNOWN_RECIPIENT:
Showmessage('A recipient did not appear in the address list; no message was sent.');
MAPI_E_USER_ABORT:
Showmessage('The user canceled the process; no message was sent.');
SUCCESS_SUCCESS:
Showmessage('MAPISendMail successfully sent the message.');
else
Showmessage('MAPISendMail failed with an unknown error code.');
end;
end;
この記事 は、Delphiが「Sendto ...」シェルコンテキストメニューコマンドをシミュレートし、プログラムで添付ファイル付きのデフォルトのメールクライアントを開く方法を示しています。
このソリューションはMAPIを必要とせず、デフォルトのメールクライアントで機能しますが、メッセージの受信者、本文、件名が自動的に入力されないため、完全ではありません。 (メッセージ本文はクリップボードを使用してコピーできます)。
これらすべての電子メール設定とその機能の概要は次のとおりです。
http://thesunstroke.blogspot.de/2017/03/how-to-configure-eurekalog-to-send-bugs.html
したがって、Shell(mailto)には近づかないでください。
Mapiは、MS電子メールクライアントでのみ機能するため、お勧めできません。
デフォルトでSimpleMAPIを設定しましたが、このチャネルから送信されたメールを受信することはめったにありません。ほとんどの電子メールはSMTPサーバー経由で受信されます。
大きな警告!!!!!!!!!
EurekaLogをアクティブにすると、ウイルス対策スキャナーからの誤検知アラームの数がはるかに多くなることがわかりました。したがって、絶対に必要な場合にのみEurekaLogを使用してください。
また、Eureka自体にもバグがたくさんあります(リリース履歴を見て、リリースされる新機能(または変更)ごとに、後でいくつかのバグが修正されることを確認してください!したがって、バグを追跡している場合は、EurekaLog自体がEXEにほとんど導入されない可能性があることに注意してください!