diff --git a/Source/Mail/Mail.Indy.pas b/Source/Mail/Mail.Indy.pas new file mode 100644 index 0000000..11d905d --- /dev/null +++ b/Source/Mail/Mail.Indy.pas @@ -0,0 +1,205 @@ +unit Mail.Indy; + +interface + +uses + System.SysUtils, + IdSMTP, + IdMessage, + IdSSLOpenSSL, + IdExplicitTLSClientServerBase, + IdText, + IdAttachmentFile, + MailInterface, + MailBase; + +type + EMailIndyException = class(EMailException); + + TMailIndy = class(TMailBase, IMail) + private const + CONNECT_TIMEOUT = 10000; + READ_TIMEOUT = 10000; + private + procedure ConfigureSmtp(const ASmtp: TIdSMTP); + procedure AddToRecipients(const AMsg: TIdMessage); + procedure AddCcRecipients(const AMsg: TIdMessage); + procedure AddBccRecipients(const AMsg: TIdMessage); + procedure AddFrom(const AMsg: TIdMessage); + procedure AddReplyTo(const AMsg: TIdMessage); + procedure AddAttachments(const AMsg: TIdMessage); + procedure AddBody(const AMsg: TIdMessage); + protected + procedure DoSend; override; + public + class function New: IMail; static; + end; + +implementation + +{ TMailIndy } + +procedure TMailIndy.AddAttachments(const AMsg: TIdMessage); +var + i: Integer; + attachment: TIdAttachmentFile; +begin + for i := 0 to Pred(GetAttachments.Count) do + begin + attachment := TIdAttachmentFile.Create(AMsg.MessageParts, GetAttachments[i]); + attachment.Headers.Add(Format('Content-ID: <%s>', [ExtractFileName(GetAttachments[i])])); + end; +end; + +procedure TMailIndy.AddBccRecipients(const AMsg: TIdMessage); +var + i: Integer; +begin + for i := 0 to Pred(GetBccRecipients.Count) do + begin + with AMsg.BccList.Add do + begin + Address := GetBccRecipients[i]; + end; + end; +end; + +procedure TMailIndy.AddBody(const AMsg: TIdMessage); +var + body: TIdText; +begin + body := TIdText.Create(AMsg.MessageParts); + body.Body.Text := GetMessages.Text; + body.ContentType := 'text/plain'; + if IsWithHTML then + begin + body.ContentType := 'text/html'; + end; +end; + +procedure TMailIndy.AddCcRecipients(const AMsg: TIdMessage); +var + i: Integer; +begin + for i := 0 to Pred(GetCcRecipients.Count) do + begin + with AMsg.CCList.Add do + begin + Address := GetCcRecipients[i]; + end; + end; +end; + +procedure TMailIndy.AddFrom(const AMsg: TIdMessage); +begin + AMsg.From.Address := GetFromAddress; + AMsg.From.Name := GetFromName; + if IsWithConfirmation then + begin + AMsg.ReceiptRecipient.Address := GetFromAddress; + AMsg.ReceiptRecipient.Name := GetFromName; + end; +end; + +procedure TMailIndy.AddReplyTo(const AMsg: TIdMessage); +begin + with AMsg.ReplyTo.Add do + begin + Address := GetReplyToAddress; + Name := GetReplyToName; + end; +end; + +procedure TMailIndy.AddToRecipients(const AMsg: TIdMessage); +var + i: Integer; +begin + for i := 0 to Pred(GetToRecipients.Count) do + begin + with AMsg.Recipients.Add do + begin + Address := GetToRecipients[i]; + end; + end; +end; + +procedure TMailIndy.ConfigureSmtp(const ASmtp: TIdSMTP); +begin + ASmtp.ConnectTimeout := CONNECT_TIMEOUT; + ASmtp.ReadTimeout := READ_TIMEOUT; + ASmtp.Host := GetHost; + ASmtp.Username := GetUsername; + ASmtp.Password := GetPassword; + ASmtp.Port := GetPort; + ASmtp.AuthType := satNone; + if IsWithAuthentication then + begin + ASmtp.AuthType := satDefault; + end; + if IsWithSSL then + begin + ASmtp.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(ASmtp); + TIdSSLIOHandlerSocketOpenSSL(ASmtp.IOHandler).SSLOptions.Method := sslvSSLv23; + TIdSSLIOHandlerSocketOpenSSL(ASmtp.IOHandler).SSLOptions.Mode := sslmClient; + ASmtp.UseTLS := utUseExplicitTLS; + end; + if IsWithTLS then + begin + ASmtp.UseTLS := utUseRequireTLS; + end; +end; + +procedure TMailIndy.DoSend; +var + smtp: TIdSMTP; + msg: TIdMessage; +begin + inherited; + smtp := TIdSMTP.Create(nil); + try + try + ConfigureSmtp(smtp); + msg := TIdMessage.Create(nil); + try + msg.Date := Now; + msg.Subject := GetSubject; + msg.ContentType := 'multipart/mixed'; + + AddToRecipients(msg); + AddCcRecipients(msg); + AddBccRecipients(msg); + AddFrom(msg); + AddReplyTo(msg); + AddAttachments(msg); + AddBody(msg); + + smtp.Connect; + try + if IsWithAuthentication then + begin + smtp.Authenticate; + end; + smtp.Send(msg); + finally + smtp.Disconnect; + end; + finally + FreeAndNil(msg); + end; + except + on E: Exception do + begin + raise EMailIndyException.Create('E-mail could not be sent!' + ^M + E.Message); + end; + end; + finally + FreeAndNil(smtp); + end; +end; + +class function TMailIndy.New: IMail; +begin + Result := TMailIndy.Create; +end; + +end. diff --git a/Source/Mail/MailBase.pas b/Source/Mail/MailBase.pas new file mode 100644 index 0000000..33169dc --- /dev/null +++ b/Source/Mail/MailBase.pas @@ -0,0 +1,338 @@ +unit MailBase; + +interface + +uses + System.SysUtils, + System.Classes, + MailInterface; + +type + TMailBase = class abstract(TInterfacedObject, IMail) + private + FHost: string; + FPort: Integer; + FUsername: string; + FPassword: string; + FSSL: Boolean; + FTLS: Boolean; + FAuthentication: Boolean; + FFromName: string; + FFromAddress: string; + FReplyToName: string; + FReplyToAddress: string; + FToRecipients: TStringList; + FCcRecipients: TStringList; + FBccRecipients: TStringList; + FConfirmation: Boolean; + FAttachments: TStringList; + FSubject: string; + FMessages: TStringList; + FHTML: Boolean; + protected + function GetHost: string; + function GetPort: Integer; + function GetUsername: string; + function GetPassword: string; + function IsWithSSL: Boolean; + function IsWithTLS: Boolean; + function IsWithAuthentication: Boolean; + function GetFromName: string; + function GetFromAddress: string; + function GetReplyToName: string; + function GetReplyToAddress: string; + function GetToRecipients: TStringList; + function GetCcRecipients: TStringList; + function GetBccRecipients: TStringList; + function IsWithConfirmation: Boolean; + function GetAttachments: TStringList; + function GetSubject: string; + function GetMessages: TStringList; + function IsWithHTML: Boolean; + + procedure DoSend; virtual; abstract; + + public + constructor Create; + destructor Destroy; override; + + function Host(const AValue: string): IMail; + function Port(const AValue: Integer): IMail; + function Username(const AValue: string): IMail; + function Password(const AValue: string): IMail; + function UsingSSL(const AValue: Boolean = True): IMail; + function UsingTLS(const AValue: Boolean = True): IMail; + function AuthenticationRequired(const AValue: Boolean = True): IMail; + + function From(const AName: string; const AAddress: string): IMail; + function ReplyTo(const AName: string; const AAddress: string): IMail; + function ToRecipient(const AAddress: string): IMail; + function CcRecipient(const AAddress: string): IMail; + function BccRecipient(const AAddress: string): IMail; + function AskForConfirmation(const AValue: Boolean = True): IMail; + + function Attachment(const AFileName: string): IMail; + + function Subject(const AValue: string): IMail; + function &Message(const AValue: string): IMail; overload; + function &Message(const AValues: TStringList): IMail; overload; + function UsingHTML(const AValue: Boolean = True): IMail; + + procedure Send; + end; + +implementation + +{ TMailBase } + +function TMailBase.AskForConfirmation(const AValue: Boolean): IMail; +begin + FConfirmation := AValue; + Result := Self; +end; + +function TMailBase.Attachment(const AFileName: string): IMail; +begin + FAttachments.Add(AFileName); + Result := Self; +end; + +function TMailBase.AuthenticationRequired(const AValue: Boolean): IMail; +begin + FAuthentication := AValue; + Result := Self; +end; + +function TMailBase.BccRecipient(const AAddress: string): IMail; +begin + FBccRecipients.Add(AAddress); + Result := Self; +end; + +function TMailBase.CcRecipient(const AAddress: string): IMail; +begin + FCcRecipients.Add(AAddress); + Result := Self; +end; + +constructor TMailBase.Create; +begin + inherited Create; + FHost := EmptyStr; + FPort := 0; + FUsername := EmptyStr; + FPassword := EmptyStr; + FSSL := False; + FTLS := False; + FAuthentication := False; + FFromName := EmptyStr; + FFromAddress := EmptyStr; + FToRecipients := TStringList.Create; + FCcRecipients := TStringList.Create; + FBccRecipients := TStringList.Create; + FConfirmation := False; + FAttachments := TStringList.Create; + FSubject := EmptyStr; + FMessages := TStringList.Create; + FHTML := False; +end; + +destructor TMailBase.Destroy; +begin + FreeAndNil(FToRecipients); + FreeAndNil(FCcRecipients); + FreeAndNil(FBccRecipients); + FreeAndNil(FAttachments); + FreeAndNil(FMessages); + inherited Destroy; +end; + +function TMailBase.From(const AName, AAddress: string): IMail; +begin + FFromName := AName; + FFromAddress := AAddress; + Result := Self; +end; + +function TMailBase.GetAttachments: TStringList; +begin + Result := FAttachments; +end; + +function TMailBase.GetBccRecipients: TStringList; +begin + Result := FBccRecipients; +end; + +function TMailBase.GetCcRecipients: TStringList; +begin + Result := FCcRecipients; +end; + +function TMailBase.GetFromAddress: string; +begin + Result := FFromAddress; +end; + +function TMailBase.GetFromName: string; +begin + Result := FFromName; +end; + +function TMailBase.GetHost: string; +begin + Result := FHost; +end; + +function TMailBase.GetMessages: TStringList; +begin + Result := FMessages; +end; + +function TMailBase.GetPassword: string; +begin + Result := FPassword; +end; + +function TMailBase.GetPort: Integer; +begin + Result := FPort; +end; + +function TMailBase.GetReplyToAddress: string; +begin + Result := FReplyToAddress; + if Result.Trim.IsEmpty then + begin + Result := FFromAddress; + end; +end; + +function TMailBase.GetReplyToName: string; +begin + Result := FReplyToName; + if Result.Trim.IsEmpty then + begin + Result := FFromName; + end; +end; + +function TMailBase.GetSubject: string; +begin + Result := FSubject; +end; + +function TMailBase.GetToRecipients: TStringList; +begin + Result := FToRecipients; +end; + +function TMailBase.GetUsername: string; +begin + Result := FUsername; +end; + +function TMailBase.Host(const AValue: string): IMail; +begin + FHost := AValue; + Result := Self; +end; + +function TMailBase.IsWithAuthentication: Boolean; +begin + Result := FAuthentication; +end; + +function TMailBase.IsWithConfirmation: Boolean; +begin + Result := FConfirmation; +end; + +function TMailBase.IsWithHTML: Boolean; +begin + Result := FHTML; +end; + +function TMailBase.IsWithSSL: Boolean; +begin + Result := FSSL; +end; + +function TMailBase.IsWithTLS: Boolean; +begin + Result := FTLS; +end; + +function TMailBase.Message(const AValue: string): IMail; +begin + FMessages.Add(AValue); + Result := Self; +end; + +function TMailBase.Message(const AValues: TStringList): IMail; +begin + FMessages.Text := AValues.Text; + Result := Self; +end; + +function TMailBase.Password(const AValue: string): IMail; +begin + FPassword := AValue; + Result := Self; +end; + +function TMailBase.Port(const AValue: Integer): IMail; +begin + FPort := AValue; + Result := Self; +end; + +function TMailBase.ReplyTo(const AName, AAddress: string): IMail; +begin + FReplyToName := AName; + FReplyToAddress := AAddress; + Result := Self; +end; + +procedure TMailBase.Send; +begin + DoSend; +end; + +function TMailBase.Subject(const AValue: string): IMail; +begin + FSubject := AValue; + Result := Self; +end; + +function TMailBase.ToRecipient(const AAddress: string): IMail; +begin + FToRecipients.Add(AAddress); + Result := Self; +end; + +function TMailBase.Username(const AValue: string): IMail; +begin + FUsername := AValue; + Result := Self; +end; + +function TMailBase.UsingHTML(const AValue: Boolean): IMail; +begin + FHTML := AValue; + Result := Self; +end; + +function TMailBase.UsingSSL(const AValue: Boolean): IMail; +begin + FSSL := AValue; + Result := Self; +end; + +function TMailBase.UsingTLS(const AValue: Boolean): IMail; +begin + FTLS := AValue; + Result := Self; +end; + +end. diff --git a/Source/Mail/MailInterface.pas b/Source/Mail/MailInterface.pas new file mode 100644 index 0000000..351bd62 --- /dev/null +++ b/Source/Mail/MailInterface.pas @@ -0,0 +1,42 @@ +unit MailInterface; + +interface + +uses + System.Classes, + System.SysUtils; + +type + EMailException = class(Exception); + + IMail = interface + ['{07C2551B-B2A6-47C6-9454-A2AE5BE884DB}'] + + function Host(const AValue: string): IMail; + function Port(const AValue: Integer): IMail; + function Username(const AValue: string): IMail; + function Password(const AValue: string): IMail; + function UsingSSL(const AValue: Boolean = True): IMail; + function UsingTLS(const AValue: Boolean = True): IMail; + function AuthenticationRequired(const AValue: Boolean = True): IMail; + + function From(const AName: string; const AAddress: string): IMail; + function ReplyTo(const AName: string; const AAddress: string): IMail; + function ToRecipient(const AAddress: string): IMail; + function CcRecipient(const AAddress: string): IMail; + function BccRecipient(const AAddress: string): IMail; + function AskForConfirmation(const AValue: Boolean = True): IMail; + + function Attachment(const AFileName: string): IMail; + + function Subject(const AValue: string): IMail; + function &Message(const AValue: string): IMail; overload; + function &Message(const AValue: TStringList): IMail; overload; + function UsingHTML(const AValue: Boolean = True): IMail; + + procedure Send; + end; + +implementation + +end. diff --git a/Source/Mail/README.md b/Source/Mail/README.md new file mode 100644 index 0000000..aa97822 --- /dev/null +++ b/Source/Mail/README.md @@ -0,0 +1,41 @@ +# E-mail para Delphi + +Framework de mailing voltada para simplificar o envio de e-mails com Delphi. +Inclui envio de e-mails com texto simples e/ou HTML, imagens incorporadas e anexos separados. +Utiliza: SMTP ou SMTPS/SSL ou SMTP + SSL. +O **Mail** fornece uma estrutura independente de driver, sendo possível extendê-lo para outros, como **Outlook**, **MAPI**, **Synapse** entre outros. + +A estrutura da mensagem de e-mail foi construída para funcionar com todos os clientes de e-mail e foi testada com muitos clientes da web, bem como alguns aplicativos de cliente convencionais, como MS Outlook ou Mozilla Thunderbird. + +# Drivers implementados +- Indy + +# Modo de usar +Adicione no library path do Delphi: + +> Source\Mail + +# Exemplo de uso + +``` +uses + MailBase, + Mail.Indy; + +procedure EnviaEmail; +begin + TMailIndy.New + .Host('smtp.exemplo.com.br') + .Port(123) + .Username('usuario') + .Password('senha_forte_do_usuario') + .From('Princess Leia', 'princess.leia@jabba.the.hutt.com') + .ToRecipient('darth.vader@darkforce.com') + .CcRecipient('mestre.yoda@jedi.com') + .BccRecipient('obi.wan.kenoby@jedi.com') + .Attachment('C:\jabba.the.hutt.kill.luke.skywalker.jpg') + .Subject('Veja só, Jabba The Hutt mata Luke Skywalker') + .Message('Caro Darth Vader, veja como ele ficou nessa imagem... hahahaha') + .Send; +end +``` \ No newline at end of file diff --git a/TestAtlas.dpr b/TestAtlas.dpr index 5412a07..2eb91e8 100644 --- a/TestAtlas.dpr +++ b/TestAtlas.dpr @@ -16,7 +16,11 @@ uses TesteSQLBuilder.Insert in 'Testes\SQLBuilder\TesteSQLBuilder.Insert.pas', TesteObjetoConexao in 'Testes\TesteObjetoConexao.pas', Types.Conexao in 'Source\Objetos\Types.Conexao.pas', - SQLBuilder in 'Source\SQLBuilder\SQLBuilder.pas'; + SQLBuilder in 'Source\SQLBuilder\SQLBuilder.pas', + TesteMail.Indy in 'Testes\Mail\TesteMail.Indy.pas', + MailInterface in 'Source\Mail\MailInterface.pas', + MailBase in 'Source\Mail\MailBase.pas', + Mail.Indy in 'Source\Mail\Mail.Indy.pas'; var runner : ITestRunner; diff --git a/TestAtlas.dproj b/TestAtlas.dproj index bbc59c3..fb2e90d 100644 --- a/TestAtlas.dproj +++ b/TestAtlas.dproj @@ -106,6 +106,10 @@ + + + + Cfg_2 Base diff --git a/Testes/Mail/TesteMail.Indy.pas b/Testes/Mail/TesteMail.Indy.pas new file mode 100644 index 0000000..a3e027f --- /dev/null +++ b/Testes/Mail/TesteMail.Indy.pas @@ -0,0 +1,45 @@ +unit TesteMail.Indy; + +interface + +uses + DUnitX.TestFramework, + DUnitX.Assert.Ex; + +type + + [ TestFixture ] + TTestSQLBuilderSelect = class( TObject ) + public + + [ Test ] + procedure sendEmail; + + end; + +implementation + +uses + MailBase, + Mail.Indy; + +{ TTestSQLBuilderSelect } + +procedure TTestSQLBuilderSelect.sendEmail; +begin + TMailIndy.New + .Host('') + .Port(0) + .Username('') + .Password('') + .From('name', 'email') + .ToRecipient('') + .CcRecipient('') + .BccRecipient('') + .Attachment('') + .Subject('') + .Message('') + .Send; +end; + +end. diff --git a/pkgAtlas.dpk b/pkgAtlas.dpk index d9876db..ae6730b 100644 --- a/pkgAtlas.dpk +++ b/pkgAtlas.dpk @@ -25,7 +25,7 @@ package pkgAtlas; {$IMAGEBASE $400000} {$DEFINE DEBUG} {$ENDIF IMPLICITBUILDING} -{$DESCRIPTION 'Atlas Framework'} +{$DESCRIPTION 'SDK Runtine Libraries'} {$RUNONLY} {$IMPLICITBUILD ON} @@ -33,12 +33,18 @@ requires rtl, vcl, FireDAC, - dbrtl; + dbrtl, + IndySystem, + IndyProtocols, + IndyCore; contains ValorPor in 'Source\ValorPor.pas', SQLBuilder in 'Source\SQLBuilder\SQLBuilder.pas', Conexao in 'Source\Objetos\Conexao.pas', - Types.Conexao in 'Source\Objetos\Types.Conexao.pas'; + Types.Conexao in 'Source\Objetos\Types.Conexao.pas', + MailInterface in 'Source\Mail\MailInterface.pas', + MailBase in 'Source\Mail\MailBase.pas', + Mail.Indy in 'Source\Mail\Mail.Indy.pas'; end. diff --git a/pkgAtlas.dproj b/pkgAtlas.dproj index ca605de..020f718 100644 --- a/pkgAtlas.dproj +++ b/pkgAtlas.dproj @@ -54,7 +54,7 @@ All pkgAtlas true - $(DCC_UnitSearchPath);modules\.dcp;modules\.dcu;modules;modules\.bpl;modules\doscommand\Source + modules\.dcp;modules\.dcu;modules;modules\.bpl;modules\doscommand\Source;$(DCC_UnitSearchPath) Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) @@ -102,10 +102,16 @@ + + + + + + Cfg_2 Base @@ -148,14 +154,14 @@ true - + - pkgAtlas.bpl true - + + pkgAtlas.bpl true