29 October, 2018

Sending e-mails with EurekaLog

EurekaLog's code can be used to easily send arbitrary e-mails from your code.

Option 1

Use EurekaLogSendEmail function from ESendMail unit. For example:
EurekaLogSendEmail('recepient@example.com', 'Subject', 'Body');
or like this:
if not EurekaLogSendEmail('"John Smith" <recepient@example.com>', 'Subject', 'Body', 'C:\Data\Attach1.txt;C:\Data\Attach2.png') then
  ShowMessage('Unable to send e-mail');
This function requires EurekaLog to be configured for your project.

It will send e-mail using already set up e-mail send method. Therefore, you have to set up at least one e-mail send method in your EurekaLog project options.

Notes:
  • This function will use the first available e-mail send method;
  • If you did not set up any e-mail send method - a shell / mailto will be used;
  • Shell / mailto does not support file attaches, so be sure to set up any other e-mail send method if you want to send e-mails with attaches;
  • You can specify e-mail address like 'account@domain.com' or '"Name" <account@domain.com>';
  • Attaches are optional, can be passed as semicolon-delimited string or as TStrings.

Option 2

If you do not want to use send settings from the project, e.g. you want to send e-mail using different account than set up for bug reports, or if you don't want to use / configure EurekaLog at all - then you may use overloaded version of EurekaLogSendEmail function from ESendMail unit to specify all the parameters manually. For example:
uses
  ETypes,    // for TResponse
  ESendMail, // for EurekaLogSendEmail 
  ESendSMTP; // for TELMailSMTPClientSender
 
var
  R: TResponse;
begin
  R := EurekaLogSendEmail(

    TELMailSMTPClientSender { which send method to use }, 

    'your-account@gmail.com' { FROM field },
    'recepient@example.com' { TO field }, 

    'Subject', 'Body', { e-mail itself }
    'smtp.gmail.com' { server }, 'your-account@gmail.com' { login }, 'your-password' { password }, 587 { port }, 
    nil { file attaches in TStrings }, 
    nil, nil, { for visual dialogs }
    ctTLS { plain, SSL or TLS });

 
  if Failed(Ord(R.SendResult)) then
    ShowMessage(R.ErrorMessage);
end;
This function does not require EurekaLog to be set up in your project. It do not use any EurekaLog project settings. You have to specify all necessary parameters manually.

Some IDE versions may be unable to resolve overload properly, producing either "ambiguous overload" or "there is no function with these arguments". If this is your case - try to use this:
var
  R: TResponse;
  PI: TELProgressIndicator; // added
  MP: TELProcessMessages; // added
begin
  PI := nil; // added
  MP := nil; // added
  R := EurekaLogSendEmail(
    // ...
    PI, MP, { for visual dialogs } // changed
    ctTLS);
  // ...
Notes:
  • SMTP client and GMail settings in the sample code above are just an example. You may use any other send method and any other e-mail server. For example, TELMailSimpleMAPISender class from ESendMailSMAPI unit for Simple MAPI, TELMailMAPISender class from ESendMailMAPI unit for MAPI, TELMailSMTPServerSender class from ESendMailSMTP for SMTP server, or TELMailShellSender class from ESendMailShell unit for shell / mailto;
  • Not all e-mail send methods require account details. For example: EurekaLogSendEmail(TELMailSimpleMAPISender, '' { not used }, 'recepient@example.com' { TO field }, 'Subject', 'Body' { e-mail itself });
  • If you want to use shell / mailto method - there is a simpler option (ESendMail unit): ShellSendMail('recepient@example.com', 'Subject', 'Message');
  • Shell / mailto does not support file attaches;
  • You can specify e-mail address like 'account@domain.com' or '"Name" <account@domain.com>';
  • You may add a visual feedback by using callback argument. See below for the example.

Option 3

EurekaLogSendEmail function is a wrapper around sender class. You may want to ignore it and just call class manually for finer control.
uses
  // ...
  EDialogSendWinAPI, // [optional] For visual dialog during sending
  ETypes; // for TResponse
 
type
  TForm1 = class(TForm)
    // ...
  private
    // [optional] For visual dialog during sending:
    FSendProgress: TSendDialogMSClassic;
    procedure ProgressIndicator(const SendState: TSendState; const Percent: Integer);
  end;
 
// ...
 
uses
  // ...
  EModules, // [optional] For CurrentEurekaLogOptions
  ESendMailSMTP; // for TELMailSMTPClientSender
 
procedure TForm1.Button1Click(Sender: TObject);
var
  MailSender: TELMailSMTPBaseSender;
  Rslt: TResponse;
begin
  MailSender := TELMailSMTPClientSender.Create;
  try
    // [optional] Copy EurekaLog project settings:
    MailSender.Options := CurrentEurekaLogOptions;
 
    // [optional] Set up send method 

    // Do this only if you did not copied CurrentEurekaLogOptions above
    MailSender.Options.SendSMTPClientHost := 'smtp.example.com';
    MailSender.Options.SendSMTPClientPort := 465;
    MailSender.Options.SendSMTPClientSSL := True;
    MailSender.Options.SendSMTPClientTLS := False;
    MailSender.Options.SendSMTPClientLogin := 'your-account@example.com';
    MailSender.Options.SendSMTPClientPassword := 'your-password';
    MailSender.Options.SendSMTPClientFrom := 'your-account@example.com';

    MailSender.Options.SendSMTPClientAdditionalHeaders := // [optional] 

            'BCC: second-recepient@example.com'#13#10 +
            'X-Priority: 1'#13#10 +
            'X-MSMail-Priority: High'#13#10 +
            'Importance: High'#13#10;
    MailSender.Options.SendSMTPClientTarget := 'recepient@example.com';
    MailSender.Options.SendSMTPClientSubject := 'Header';
    MailSender.Options.SendSMTPClientMessage := 'Body';
    MailSender.Options.SendSMTPClientAppendLogs := False;
    MailSender.Options.SendSMTPClientUseRealEMail := False;
 
    // [optional] Attach a file on disk:
    MailSender.AttachedFiles.Add('C:\Data\Attach1.txt');
    // [optional] Attach a virtual file (TStream):
    MailSender.AttachedFiles.AddObject('Attach2.txt', Stream);
 
    // [optional] For visual dialog during sending:
    MailSender.ProgressIndicator := ProgressIndicator;
    FSendProgress := TSendDialogMSClassic.Create(Handle, MailSender.Options);
    try

 
      // Actual send
      Rslt := MailSender.SendMessage;

 
    // [optional] For visual dialog during sending:
    finally
      FreeAndNil(FSendProgress);
    end;
 
    if Failed(Ord(Rslt.SendResult)) then
      ShowMessage(Rslt.ErrorMessage);
 
  finally
    FreeAndNil(MailSender);
  end;
end;
 
// [optional] For visual dialog during sending:
procedure TForm1.ProgressIndicator(const SendState: TSendState; const Percent: Integer);
begin
  if not Assigned(FSendProgress) then
    Exit;

  FSendProgress.Progress := Percent;

  case SendState of
    ssInit:
      FSendProgress.DialogLabel := 
        FSendProgress.Options.CustomizedExpandedTexts[mtSendDialog_Connecting];
    ssResolvingDNS:
      FSendProgress.DialogLabel := 
        FSendProgress.Options.CustomizedExpandedTexts[mtSendDialog_Resolving];
    ssConnecting:
      FSendProgress.DialogLabel := 
        FSendProgress.Options.CustomizedExpandedTexts[mtSendDialog_Connecting];
    ssLogin:
      FSendProgress.DialogLabel := 
        FSendProgress.Options.CustomizedExpandedTexts[mtSendDialog_Login];
    ssSelecting:
      FSendProgress.DialogLabel := 
        FSendProgress.Options.CustomizedExpandedTexts[mtSendDialog_SelectProject];
    ssSearching:
      FSendProgress.DialogLabel := 
        FSendProgress.Options.CustomizedExpandedTexts[mtSendDialog_Searching];
    ssReading:
      FSendProgress.DialogLabel :=
        FSendProgress.Options.CustomizedExpandedTexts[mtSendDialog_SelectProject];
    ssSending:
      FSendProgress.DialogLabel := 
        FSendProgress.Options.CustomizedExpandedTexts[mtSendDialog_Sending];
    ssModifying:
      FSendProgress.DialogLabel := 
        FSendProgress.Options.CustomizedExpandedTexts[mtSendDialog_Modifying];
    ssDisconnecting:
      FSendProgress.DialogLabel := 
        FSendProgress.Options.CustomizedExpandedTexts[mtSendDialog_Disconnecting];
    ssDone:
      FSendProgress.DialogLabel := 
        FSendProgress.Options.CustomizedExpandedTexts[mtSendDialog_Disconnected];
  end;
end;