Mail := MailBuilder .SetSender('no-reply@test.com') .AddRecipient('test@test.com') .AddRecipient('test@test.com') .AddCC('manager@test.com') .AddBCC('archive@test.com') .SetSubject('This is a subject') .SetContent('This is the content') .AddAttachment('Test.pdf', 'application/pdf') .Build(); Mail.Send();
unit Helpers.Email; interface uses SysUtils, Email.MailAttachment, Email.MailBuilder, Email.Mail, Email.MailServerBuilder, Email.MailPriority, Helpers.logging; type TMailAttachment = Email.MailAttachment.TMailAttachment; TMailBuilder = Email.MailBuilder.TMailBuilder; TMailBuildResult = Email.MailBuilder.TMailBuildResult; TMailServerSettings = Email.MailServerBuilder.TMailServerSettings; TSendMailResult = Email.MailServerBuilder.TSendMailResult; TMailServerBuilder = Email.MailServerBuilder.TMailServerBuilder; TMailPriority = Email.MailPriority.TMailPriority; function MailBuilder(AUseDefaults: Boolean = true): TMailBuilder; var MailServer: TMailServerBuilder; var MailLogger: TLogger; implementation function MailBuilder(AUseDefaults: Boolean = true): TMailBuilder; begin Result := TMailBuilder.Create; if (AUseDefaults) then MailServer.AddDefaults(Result); end; var DefaultMailLoggingConfig: TLoggerConfig; initialization MailServer:= TMailServerBuilder.Create; MailServer.LoadFromIniFile('.\SMTP.ini'); DefaultMailLoggingConfig.FileName := '.\log\SMTP.log'; DefaultMailLoggingConfig.LogLevel := ltTrace; MailLogger := TLogger.Create(TLogger.ReadConfig('.\smtp-logging.ini', DefaultMailLoggingConfig)); MailLogger.Info('SMTP log started.'); finalization FreeAndNil(MailServer); FreeAndNil(MailLogger) end. /////// unit Email.MailBuilder; interface uses variants, SysUtils, System.Classes, System.Generics.Collections, Email.Mail, Email.MailPriority; type TMailBuildResult = record Valid: Boolean; ExecptionMessage: string; Mail: TMail; end; TMailBuilder = class private FMail: TMail; function _AddTo(AEmail: string): TMailBuilder; function _AddCC(AEmail: string): TMailBuilder; function _AddBCC(AEmail: string): TMailBuilder; public constructor Create; destructor Destroy; override; function SetFrom(AEmail: string): TMailBuilder; function AddTo(AEmail: string): TMailBuilder; overload; function AddTo(AEmails: TArray<string>): TMailBuilder; overload; function AddCC(AEmail: string): TMailBuilder; overload; function AddCC(AEmails: TArray<string>): TMailBuilder; overload; function AddBCC(AEmail: string): TMailBuilder; overload; function AddBCC(AEmails: TArray<string>): TMailBuilder; overload; function SetPriority(APriority: TMailPriority): TMailBuilder; function ClearTo(): TMailBuilder; function ClearCC(): TMailBuilder; function ClearBCC(): TMailBuilder; function SetSubject(AText: string): TMailBuilder; function ClearContent: TMailBuilder; function AddContent(AText: string): TMailBuilder; function ClearHtmlContent: TMailBuilder; function AddHtmlContent(AText: string): TMailBuilder; function AddAttachment(AAttachmentName: string; AContentType: string; AContent: TStream; AFreeAfterSend: Boolean = false; AContentId: string = ''): TMailBuilder; function AddFileAttachment(AFileNames: TArray<string>): TMailBuilder; overload; function AddFileAttachment(AFileName: string): TMailBuilder; overload; function GetDebugContent: string; function Build: TMailBuildResult; class function IsEmailaddressValid(AEmail: String): Boolean; end; implementation uses Email.MailAttachment, Email.MailServerBuilder; constructor TMailBuilder.Create; begin FMail := TMail.Create; end; destructor TMailBuilder.Destroy; begin FreeAndNil(FMail); inherited; end; function TMailBuilder.GetDebugContent: string; var stringList: TStringList; begin stringList := TStringList.Create; try stringList.Add('From: '); stringList.Add(Self.FMail.From); stringList.Add('-------------------------------------------------------------'); stringList.Add('To: '); stringList.Add(string.Join('; ' ,Self.FMail.ToList.ToArray)); stringList.Add('-------------------------------------------------------------'); stringList.Add('Cc: '); stringList.Add(string.Join('; ' ,Self.FMail.CCList.ToArray)); stringList.Add('-------------------------------------------------------------'); stringList.Add('Bcc: '); stringList.Add(string.Join('; ' ,Self.FMail.BCCList.ToArray)); stringList.Add('-------------------------------------------------------------'); stringList.Add('Subject: '); stringList.Add(Self.FMail.Subject); stringList.Add('-------------------------------------------------------------'); stringList.Add('Content: '); stringList.Add(Self.FMail.Content); stringList.Add('-------------------------------------------------------------'); Result := stringList.Text; finally stringList.Free; end; end; class function TMailBuilder.IsEmailaddressValid(AEmail: string): Boolean; begin Result := AEmail.Trim() <> ''; end; function TMailBuilder.Build: TMailBuildResult; begin Result.Valid := false; if not IsEmailaddressValid(FMail.From) then begin Result.ExecptionMessage := 'Invalid mail "From" address'; end else if FMail.ToList.Count = 0 then begin Result.ExecptionMessage := 'No valid mail "To" address'; end else begin Result.Valid := true; Result.Mail := FMail; end; end; function TMailBuilder.SetFrom(AEmail: string): TMailBuilder; begin if IsEmailaddressValid(AEmail) then FMail.From := Trim(AEmail); Result := self; end; function TMailBuilder.SetPriority(APriority: TMailPriority): TMailBuilder; begin FMail.Priority := APriority; result := self; end; function TMailBuilder.AddTo(AEmails: TArray<string>): TMailBuilder; var str: string; begin for str in AEmails do _AddTo(str); Result := self; end; function TMailBuilder.AddTo(AEmail: string): TMailBuilder; begin result := AddTo(AEmail.Split([';'])); end; function TMailBuilder._AddTo(AEmail: string): TMailBuilder; begin if IsEmailaddressValid(AEmail) then FMail.ToList.Add(Trim(AEmail)); Result := self; end; function TMailBuilder.AddCC(AEmails: TArray<string>): TMailBuilder; var str: string; begin for str in AEmails do _AddCC(str); Result := self; end; function TMailBuilder.AddCC(AEmail: string): TMailBuilder; begin result := AddCC(AEmail.Split([';'])); end; function TMailBuilder._AddCC(AEmail: string): TMailBuilder; begin if IsEmailaddressValid(AEmail) then FMail.CCList.Add(Trim(AEmail)); Result := self; end; function TMailBuilder.ClearContent(): TMailBuilder; begin FMail.Content := ''; Result := self; end; function TMailBuilder.ClearHtmlContent(): TMailBuilder; begin FMail.HtmlContent := ''; Result := self; end; function TMailBuilder.AddContent(AText: string): TMailBuilder; begin FMail.Content := FMail.Content + AText; Result := self; end; function TMailBuilder.AddBCC(AEmails: TArray<string>): TMailBuilder; var str: string; begin for str in AEmails do _AddBCC(str); Result := self; end; function TMailBuilder.AddBCC(AEmail: string): TMailBuilder; begin Result := AddBCC(AEmail.Split([';'])); end; function TMailBuilder._AddBCC(AEmail: string): TMailBuilder; begin if IsEmailaddressValid(AEmail) then FMail.BCCList.Add(Trim(AEmail)); Result := self; end; function TMailBuilder.SetSubject(AText: string): TMailBuilder; begin FMail.Subject := AText; Result := self; end; function TMailBuilder.AddAttachment(AAttachmentName, AContentType: string; AContent: TStream; AFreeAfterSend: Boolean = false; AContentId: string = '') : TMailBuilder; var attachment: TMailAttachment; begin if not Assigned(AContent) then Exit(self); attachment.Name := AAttachmentName; attachment.ContentType := AContentType; attachment.Data := AContent; attachment.ContentId := AContentId; attachment.FreeAfterSend := AFreeAfterSend; FMail.Attachments.Add(attachment); Result := self; end; function TMailBuilder.AddFileAttachment(AFileNames: TArray<string>): TMailBuilder; var str: string; begin for str in AFileNames do AddFileAttachment(str); Result := self; end; function TMailBuilder.AddFileAttachment(AFileName: string): TMailBuilder; var fileStream : TFileStream; mimetable : TIdThreadSafeMimeTable; ContentType: string; begin if not TFile.Exists(AFileName) then Exit(self); fileStream := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyNone); // TFile.OpenRead(AFileName); mimetable := TIdThreadSafeMimeTable.Create(true); try ContentType := mimetable.GetFileMIMEType(AFileName); finally mimetable.Free; end; Result := AddAttachment(TPath.GetFileName(fileStream.FileName), ContentType, fileStream, true); end; function TMailBuilder.AddHtmlContent(AText: string): TMailBuilder; begin FMail.HtmlContent := FMail.HtmlContent + AText; Result := self; end; function TMailBuilder.ClearTo: TMailBuilder; begin FMail.ToList.Clear; Result := self; end; function TMailBuilder.ClearCC: TMailBuilder; begin FMail.CCList.Clear; Result := self; end; function TMailBuilder.ClearBCC: TMailBuilder; begin FMail.BCCList.Clear; Result := self; end; end. ///////// unit Email.MailServerBuilder; interface uses variants, SysUtils, System.Classes, System.Generics.Collections, Email.Mail, Email.MailBuilder, Email.MailAttachment; type TMailServerSettings = class public Host: string; Port: Integer; UserName: string; Password: string; UseTLS: Boolean; DefaultFrom: string; DefaultTo: string; DefaultCC: string; DefaultBCC: string; DebugOverride: string; OverrideEmail: string; ReferencePrefix: string; end; TMailServerBuilder = class; TSendMailResult = record public Success: Boolean; ExceptionMessage: string; end; TMailServerBuilder = class FServerSettings: TMailServerSettings; function LoadFromIniFile(ACompleteFilename: string): TMailServerBuilder; function SetHost(AHost: string; APort: integer; AUseTLS: boolean = false): TMailServerBuilder; function SetCredentials(AUserName: string; APassword: string): TMailServerBuilder; function SendMail(AMailBuilder: TMailBuilder) : TSendMailResult; function GetReferenceText(AText: string): string; procedure AddDefaults(AMailBuilder: TMailBuilder); constructor Create; destructor Destroy; override; end; const EmailConfigSalt: word = 5326; implementation uses Helpers.Email; constructor TMailServerBuilder.Create; begin FServerSettings := TMailServerSettings.Create; end; destructor TMailServerBuilder.Destroy; begin FreeAndNil(FServerSettings); inherited; end; function TMailServerBuilder.GetReferenceText(AText: string): string; begin Result := #13#10+FServerSettings.ReferencePrefix+' '+AText; end; { [SMTP] host= port= useTLS=0 Username= Password= Override=Email@email.com (keep mail the same, but clean To,Cc, Bcc) DebugOverride=test@test.com (Set everything in body of mail) ReferencePrefix= referentienummer: [DEFAULTS] From=test@test.com To= CC= BCC=test@test.com } function TMailServerBuilder.LoadFromIniFile(ACompleteFilename: string): TMailServerBuilder; var iniFile: TMemIniFile; path: string; Section: string; password: string; EncriptedPassword: string; begin path := ACompleteFilename; iniFile := TMemIniFile.Create(path, TEncoding.ANSI, false); try Section:= 'SMTP'; FServerSettings.Host := iniFile.ReadString(Section, 'host', ''); FServerSettings.Port := iniFile.ReadInteger(Section, 'port', 0); FServerSettings.UserName := iniFile.ReadString(Section, 'Username', ''); password := iniFile.ReadString(Section, 'Password', ''); EncriptedPassword := iniFile.ReadString(Section, 'PasswordEncrypted', ''); if (password.Trim() <> '') then begin EncriptedPassword := TEncryptionHelper.Encrypt(password, EmailConfigSalt); iniFile.WriteString(Section, 'PasswordEncrypted', EncriptedPassword); iniFile.WriteString(Section, 'Password', ''); iniFile.UpdateFile; end; FServerSettings.Password := TEncryptionHelper.Decrypt(EncriptedPassword, EmailConfigSalt); FServerSettings.UseTLS := iniFile.ReadBool(Section, 'UseTLS', false); FServerSettings.DebugOverride := iniFile.ReadString(Section, 'DebugOverride', ''); FServerSettings.OverrideEmail := iniFile.ReadString(Section, 'Override', ''); FServerSettings.ReferencePrefix := iniFile.ReadString(Section, 'ReferencePrefix', ''); Section:= 'DEFAULTS'; FServerSettings.DefaultFrom := iniFile.ReadString(Section, 'From', ''); FServerSettings.DefaultTo := iniFile.ReadString(Section, 'To', ''); FServerSettings.DefaultCC := iniFile.ReadString(Section, 'CC', ''); FServerSettings.DefaultBCC := iniFile.ReadString(Section, 'BCC', ''); finally iniFile.Free; end; Result := Self; end; function TMailServerBuilder.SendMail(AMailBuilder: TMailBuilder): TSendMailResult; var smtpClient : TidSmtp; mailMessage : TIdMessage; email: string; attachment: TMailAttachment; idAttachment : TIdAttachmentMemory; SendMailResult : TSendMailResult; textPart : TIdText; SSL: TIdSSLIOHandlerSocketOpenSSL; mail : TMail; mailBuildResult : TMailBuildResult; debugContent: string; begin try debugContent := AMailBuilder.GetDebugContent; if TMailBuilder.IsEmailaddressValid(FServerSettings.DebugOverride) then begin AMailBuilder .ClearTo() .ClearCC() .ClearBCC() .AddTo(FServerSettings.DebugOverride) .ClearContent() .AddContent(debugContent); end else if TMailBuilder.IsEmailaddressValid(FServerSettings.OverrideEmail) then begin AMailBuilder .ClearTo() .ClearCC() .ClearBCC() .AddTo(FServerSettings.OverrideEmail); end; mailBuildResult := AMailBuilder.Build; if (mailBuildResult.Valid) then begin mail := mailBuildResult.Mail; end else begin MailLogger.Warning('Failed to build valid Email, Err:' + mailBuildResult.ExecptionMessage); Result.Success := false; Result.ExceptionMessage := mailBuildResult.ExecptionMessage; Exit; end; smtpClient := TIdSMTP.Create; if FServerSettings.UseTLS then begin SSL := TIdSSLIOHandlerSocketOpenSSL.Create(nil); SSL.SSLOptions.Method := sslvTLSv1; // SSL.SSLOptions.SSLVersions := [sslvSSLv2, sslvSSLv23, sslvSSLv3, sslvTLSv1, sslvTLSv1_1, sslvTLSv1_2]; SSL.SSLOptions.Mode := sslmClient; // or sslmUnassigned ? SSL.SSLOptions.VerifyMode := []; SSL.SSLOptions.VerifyDepth := 0; smtpClient.IOHandler := SSL; smtpClient.UseTLS := utUseExplicitTLS; end; mailMessage:= TIdMessage.Create(nil); try smtpClient.Host := FServerSettings.Host; smtpClient.Port := FServerSettings.Port; smtpClient.UserName := FServerSettings.UserName; smtpClient.Password := FServerSettings.Password; mailMessage.Body.Clear; mailMessage.ContentType := 'multipart/related'; mailMessage.Priority := TIdMessagePriority(mail.Priority); mailMessage.From.Text := mail.From; mailMessage.Subject := mail.Subject; for email in mail.ToList do mailMessage.Recipients.Add().Text := email; for email in mail.CCList do mailMessage.CCList.Add().Text := email; for email in mail.BCCList do mailMessage.BCCList.Add().Text := email; mailMessage.ContentType := 'multipart/related'; if (mail.HtmlContent.Length > 0) then begin textPart := TIdText.Create(mailMessage.MessageParts); textPart.Body.Text := mail.HtmlContent; textPart.ContentType := 'text/html'; textPart.ContentDisposition := 'inline'; end; textPart := TIdText.Create(mailMessage.MessageParts); textPart.Body.Text := mail.Content; textPart.ContentType := 'text/plain'; textPart.ContentDisposition := 'inline'; for attachment in mail.Attachments do begin attachment.Data.Position := 0; idAttachment := TIdAttachmentMemory.Create(mailMessage.MessageParts, attachment.Data); idAttachment.ContentType := attachment.ContentType; idAttachment.ContentID := attachment.ContentId; idAttachment.FileName := attachment.Name; end; MailLogger.Trace(FServerSettings.Host +':'+ IntToStr(FServerSettings.Port) + '; Username:' + FServerSettings.UserName); smtpClient.Connect; smtpClient.Send(mailMessage); smtpClient.Disconnect(true); finally for attachment in mail.Attachments do begin if (attachment.FreeAfterSend) then begin attachment.Data.Free; end; end; FreeAndNil(mailMessage); FreeAndNil(smtpClient); FreeAndNil(AMailBuilder); end; SendMailResult.Success := true; MailLogger.Info('Mail successfully sent.'); Except on E: Exception do begin SendMailResult.Success := false; SendMailResult.ExceptionMessage := E.Message; MailLogger.Error('Failed to send mail.', E); MailLogger.Trace('FAILED EMAIL CONTENT: ' + #13#10 + debugContent); end; end; Result := SendMailResult; end; function TMailServerBuilder.SetCredentials(AUserName: string; APassword: string): TMailServerBuilder; begin FServerSettings.UserName := AUserName; FServerSettings.Password := APassword; result := Self; end; procedure TMailServerBuilder.AddDefaults(AMailBuilder: TMailBuilder); begin AMailBuilder.SetFrom(FServerSettings.DefaultFrom); AMailBuilder.AddTo(FServerSettings.DefaultTo.Split([';', ',']) ); AMailBuilder.AddCC(FServerSettings.DefaultCC.Split([';', ','])); AMailBuilder.AddBCC(FServerSettings.DefaultBCC.Split([';', ','])); end; function TMailServerBuilder.SetHost(AHost: string; APort: integer; AUseTLS: boolean): TMailServerBuilder; begin FServerSettings.Host := AHost; FServerSettings.Port := APort; FServerSettings.UseTLS := AUseTLS; result := Self; end; end.
415500cookie-checkDelphi Builder example