Difference between revisions of "lNet examples"

From Lazarus wiki
Jump to navigationJump to search
(→‎Lazarus SMTP client example for macOS: Add SourceForge URL for example project code)
 
(18 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 
__TOC__
 
__TOC__
  
{{Tip|You can use the non-visual code in Lazarus applications. This is necessary for macOS because lNet visual components do not support the Cocoa or Carbon widget sets. To successfully compile the lNet library and non-visual code examples on macOS requires the lNet version available from https://github.com/trevoz/lnet which has many changes made to it so that it will compile on macOS 10.14 and later with FPC 3.3.1 [16 March 2022].}}
+
{{Tip|You can use the non-visual code in Lazarus applications. This is necessary for macOS because lNet visual components do not support the Cocoa or Carbon widget sets. To successfully compile the lNet library and non-visual code examples with FPC 3.2.2 or FPC 3.3.1 requires the lNet version available from https://github.com/trevoz/lnet which has many changes made to it so that it will compile with a modern FPC and to support TLSv1.3.}}
  
 
== lNet provided console (non-visual) code examples ==
 
== lNet provided console (non-visual) code examples ==
  
In the lNet <tt>examples/console/</tt> directory you will find example programs for:
+
In the '''[[lNet]]''' <tt>examples/console/</tt> directory you will find example programs for:
  
 
* FTP
 
* FTP
Line 26: Line 26:
 
These examples will not compile on macOS because the lNet visual components have no interface bindings for the Cocoa or Carbon widget sets.
 
These examples will not compile on macOS because the lNet visual components have no interface bindings for the Cocoa or Carbon widget sets.
  
== Lazarus SMTP client example for macOS ==
+
== Lazarus SMTP client example ==
  
 
This is a simple Lazarus SMTP client.  
 
This is a simple Lazarus SMTP client.  
Line 32: Line 32:
 
* Memo1 contains the body of the email message.  
 
* Memo1 contains the body of the email message.  
 
* For debugging purposes, Memo2 is used to record the log of the email transaction.  
 
* For debugging purposes, Memo2 is used to record the log of the email transaction.  
* STARTTLS is enabled (with FSMTP.StartTLS;). The encrypted TLS (Transport Layer Security) connection is used when communicating between the mail server and the client to provide better security.
+
* Compiles with FPC 3.2.2 and FPC 3.3.1 on FreeBSD (tested on 12-RELEASE), macOS 10.12+, Linux (Ubuntu 21.10) and Windows 32 bit and 64 bit (tested on Windows 10).
* Requires FPC 3.3.1 as of 16 March 2022 to compile successfully - does not compile with FPC 3.2.2.
+
* STARTTLS is enabled (with FSMTP.StartTLS;). The encrypted TLS (Transport Layer Security) connection is used when communicating between the mail server and the client to provide better security. FreeBSD 12, macOS 10.12+ and Windows 10 pick TLS v1.3, Linux (Ubuntu 21.10) picks TLS v1.2 (except Linux has problems - see below).
* lNet library for macOS 10.14 and later from https://github.com/trevoz/lnet is required.
+
* Note: TLS does not work in Linux due to an inscrutable epoll error (Error on epoll [4]: Interrupted system call) from the Linux-specific <tt>lib/sys/lepolleventer.inc</tt> file. Fixes welcome :-)
* Add path to the lNet library units to the Project Options > Paths - "Other unit files".
+
* TLS v1.3 has been added.
 +
* All insecure SSL and TLS methods have been removed (ie SSL2, SSL3, TLSv1, TLSv1.1) leaving TLS v1.2 and v1.3.
 +
* The lNet library from https://github.com/trevoz/lnet is required.
 +
* Add the path to the lNet library units to the Project Options > Paths - "Other unit files".
  
 
<syntaxhighlight lang=pascal>
 
<syntaxhighlight lang=pascal>
Line 217: Line 220:
 
Here's a copy of the transaction on the mail server for the above message:
 
Here's a copy of the transaction on the mail server for the above message:
  
  Mar 18 16:22:33 shadow sm-mta[66179]: 22I5MXc3066179: Milter (milter-relay): init success to negotiate
+
  Mar 18 16:22:33 shadow sm-mta[66179]: 221820LG031423: Milter (milter-relay): init success to negotiate
  Mar 18 16:22:33 shadow sm-mta[66179]: 22I5MXc3066179: Milter (milter-regex): init success to negotiate
+
  Mar 18 16:22:33 shadow sm-mta[66179]: 221820LG031423: Milter (milter-regex): init success to negotiate
  Mar 18 16:22:33 shadow sm-mta[66179]: 22I5MXc3066179: Milter (greylist): init success to negotiate
+
  Mar 18 16:22:33 shadow sm-mta[66179]: 221820LG031423: Milter (greylist): init success to negotiate
  Mar 18 16:22:33 shadow sm-mta[66179]: 22I5MXc3066179: Milter: connect to filters
+
  Mar 18 16:22:33 shadow sm-mta[66179]: 221820LG031423: Milter: connect to filters
  Mar 18 16:22:33 shadow sm-mta[66179]: 22I5MXc3066179: STARTTLS=server, relay=macmini8.example.org [192.168.1.21], version=TLSv1.2, verify=NO, cipher=ECDHE-RSA-AES256-GCM-SHA384, bits=256/256
+
  Mar 18 16:22:33 shadow sm-mta[66179]: 221820LG031423: STARTTLS=server, relay=macmini8.example.org [192.168.1.21], version=TLSv1.3, verify=NO, cipher=TLS_AES_256_GCM_SHA384, bits=256/256
  Mar 18 16:22:34 shadow milter-greylist[25940]: 22I5MXc3066179: addr = macmini8.example.org[192.168.1.21], from = <trev@nowhereonearth.com>, rcpt = <trev@example.org>
+
  Mar 18 16:22:34 shadow milter-greylist[25940]: 221820LG031423: addr = macmini8.example.org[192.168.1.21], from = <trev@nowhereonearth.com>, rcpt = <trev@example.org>
 
  Mar 18 16:22:34 shadow milter-greylist[25940]: whitelisted by {greylist}
 
  Mar 18 16:22:34 shadow milter-greylist[25940]: whitelisted by {greylist}
  Mar 18 16:22:34 shadow sm-mta[66179]: 22I5MXc3066179: Subject:Test.email
+
  Mar 18 16:22:34 shadow sm-mta[66179]: 221820LG031423: Subject:Test.email
  Mar 18 16:22:34 shadow sm-mta[66179]: 22I5MXc3066179: from=<trev@nowhereonearth.com>, size=73, class=0, nrcpts=1, msgid=<202203180522.22I5MXc3066179@shadow.example.org>, proto=ESMTP, daemon=IPv4, relay=macmini8.example.org [192.168.1.21]
+
  Mar 18 16:22:34 shadow sm-mta[66179]: 221820LG031423: from=<trev@nowhereonearth.com>, size=73, class=0, nrcpts=1, msgid=<202203180522.22I5MXc3066179@shadow.example.org>, proto=ESMTP, daemon=IPv4, relay=macmini8.example.org [192.168.1.21]
  Mar 18 16:22:34 shadow sm-mta[66179]: 22I5MXc3066179: Milter (greylist) add: header: X-Greylist: Message whitelisted by Sendmail access database, not delayed by milter-greylist-4.6.4 (shadow.example.org [192.168.1.4]); Fri, 18 Mar 2022 16:22:34 +1100 (AEDT)
+
  Mar 18 16:22:34 shadow sm-mta[66179]: 221820LG031423: Milter (greylist) add: header: X-Greylist: Message whitelisted by Sendmail access database, not delayed by milter-greylist-4.6.4 (shadow.example.org [192.168.1.4]); Fri, 18 Mar 2022 16:22:34 +1100 (AEDT)
  Mar 18 16:22:34 shadow sm-mta[66179]: 22I5MXc3066179: Milter accept: message
+
  Mar 18 16:22:34 shadow sm-mta[66179]: 221820LG031423: Milter accept: message
  Mar 18 16:22:34 shadow sm-mta[66180]: 22I5MXc3066179: to=<trev@example.org>, delay=00:00:00, xdelay=00:00:00, mailer=local, pri=30597, relay=local, dsn=2.0.0, stat=Sent
+
  Mar 18 16:22:34 shadow sm-mta[66180]: 221820LG031423: to=<trev@example.org>, delay=00:00:00, xdelay=00:00:00, mailer=local, pri=30597, relay=local, dsn=2.0.0, stat=Sent
  
 
The full project source code is available for download from [https://sourceforge.net/p/lazarus-wiki-projects/code/ci/767b0a105a3ec6f4c8f54aab861984f7f90be81f/tree/laz_lnet_smtp/ SourceForge].
 
The full project source code is available for download from [https://sourceforge.net/p/lazarus-wiki-projects/code/ci/767b0a105a3ec6f4c8f54aab861984f7f90be81f/tree/laz_lnet_smtp/ SourceForge].
Line 235: Line 238:
  
 
* [[lNet]]
 
* [[lNet]]
 +
* [[Synapse - Email Examples]]
 +
* [https://www.ietf.org/rfc/rfc2821.txt RFC2821] Simple Mail Transfer Protocol (SMTP)
 +
* [https://www.ietf.org/rfc/rfc3207.txt RFC3207] SMTP Service Extension for Secure SMTP over Transport Layer Security (TLS)
 +
* [https://www.ietf.org/rfc/rfc5246.txt RFC5246] The Transport Layer Security (TLS) Protocol Version 1.2
 +
* [https://www.ietf.org/rfc/rfc8446.txt RFC8446] The Transport Layer Security (TLS) Protocol Version 1.3
 +
  
 
[[Category:Networking]]
 
[[Category:Networking]]
 
[[Category:Components]]
 
[[Category:Components]]
 
[[Category:Example programs]]
 
[[Category:Example programs]]

Latest revision as of 02:33, 18 May 2022

Note-icon.png

Tip: You can use the non-visual code in Lazarus applications. This is necessary for macOS because lNet visual components do not support the Cocoa or Carbon widget sets. To successfully compile the lNet library and non-visual code examples with FPC 3.2.2 or FPC 3.3.1 requires the lNet version available from https://github.com/trevoz/lnet which has many changes made to it so that it will compile with a modern FPC and to support TLSv1.3.

lNet provided console (non-visual) code examples

In the lNet examples/console/ directory you will find example programs for:

  • FTP
  • HTTP
  • SMTP
  • TCP
  • Telnet
  • UDP

lNet provided visual code examples

In the lNet examples/visual/ directory you will find example programs for:

  • FTP
  • HTTP
  • SMTP
  • TCP and UDP (combined)
  • Telnet

These examples will not compile on macOS because the lNet visual components have no interface bindings for the Cocoa or Carbon widget sets.

Lazarus SMTP client example

This is a simple Lazarus SMTP client.

  • Memo1 contains the body of the email message.
  • For debugging purposes, Memo2 is used to record the log of the email transaction.
  • Compiles with FPC 3.2.2 and FPC 3.3.1 on FreeBSD (tested on 12-RELEASE), macOS 10.12+, Linux (Ubuntu 21.10) and Windows 32 bit and 64 bit (tested on Windows 10).
  • STARTTLS is enabled (with FSMTP.StartTLS;). The encrypted TLS (Transport Layer Security) connection is used when communicating between the mail server and the client to provide better security. FreeBSD 12, macOS 10.12+ and Windows 10 pick TLS v1.3, Linux (Ubuntu 21.10) picks TLS v1.2 (except Linux has problems - see below).
  • Note: TLS does not work in Linux due to an inscrutable epoll error (Error on epoll [4]: Interrupted system call) from the Linux-specific lib/sys/lepolleventer.inc file. Fixes welcome :-)
  • TLS v1.3 has been added.
  • All insecure SSL and TLS methods have been removed (ie SSL2, SSL3, TLSv1, TLSv1.1) leaving TLS v1.2 and v1.3.
  • The lNet library from https://github.com/trevoz/lnet is required.
  • Add the path to the lNet library units to the Project Options > Paths - "Other unit files".
unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls,
  lnet, lsmtp, lnetssl;

type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;      // Send email button
    BodyLabel: TLabel;
    EmailLogLabel: TLabel;
    Memo1: TMemo;          // Mail content
    Memo2: TMemo;          // Mail log
    SubjectEdit: TEdit;    // Mail subject
    SubjectLabel: TLabel;
    MailToEdit: TEdit;     // MailTo
    MailToLabel: TLabel;
    MailFromEdit: TEdit;   // MailFrom
    MailFromLabel: TLabel;
    procedure Button1Click(Sender: TObject);
  private

  public

  end;

  type

  { TLSMTPClientTest }

  TLSMTPClientTest = class(TComponent)
   private
    FSMTP: TLSMTPClient; // this is THE smtp connection
    FSSL: TLSSLSession;
    FQuit: Boolean;  // helper for main loop
    { these events are used to see what happens on the SMTP connection. They are used via "CallAction".
      OnReceive will get fired whenever new data is received from the SMTP server.
      OnConnect will get fired when connecting to the SMTP server ends with success.
      OnDisconnect will get fired when the other side closes the connection gracefully.
      OnError will get called when any kind of error occurs on the connection. }
    procedure OnReceive(aSocket: TLSocket);
    procedure OnConnect(aSocket: TLSocket);
    procedure OnDisconnect(aSocket: TLSocket);
    procedure OnError(const msg: string; aSocket: TLSocket);
    { This event is used to monitor TLS session handshake. If SSL or TLS is used
      we will know if the handshake went ok if this event is fired on the session }
    procedure OnSSLConnect(aSocket: TLSocket);
   public
    constructor Create(aOwner: TComponent); override;
    procedure Run; // main SMTP processing loop
  end;

var
  Form1: TForm1;
  SMTP: TLSMTPClientTest;

implementation

{$R *.lfm}

{ TForm1 }

procedure TLSMTPClientTest.OnReceive(aSocket: TLSocket);
var
  s: string;
begin
  if FSMTP.GetMessage(s) > 0 then // if we actually received something from SMTP server
    begin
     Form1.Memo2.Append(s);       // inform user

     // Check server response to see if we should quit because mail delivered
     If pos('250 2.0.0',s) <> 0 then
       FQuit := True
    end;
end;

procedure TLSMTPClientTest.OnConnect(aSocket: TLSocket);
begin
  Form1.Memo2.Append('Connected' + LineEnding); // inform user of successful connect
end;

procedure TLSMTPClientTest.OnDisconnect(aSocket: TLSocket);
begin
  Form1.Memo2.Append('Lost connection'); // inform user about lost connection
  FQuit := True;      // since SMTP shouldn't do this unless we issued a QUIT,
                      // consider it to be end of session and quit it.
end;

procedure TLSMTPClientTest.OnError(const msg: string; aSocket: TLSocket);
begin
  Form1.Memo2.Append(msg);  // inform user of error
  FQuit := True;            // and quit session.
end;

procedure TLSMTPClientTest.OnSSLConnect(aSocket: TLSocket);
begin
  Form1.Memo2.Append('SSL session handshake was successful');
end;

constructor TLSMTPClientTest.Create(aOwner: TComponent);
begin
  inherited;
  FQuit := False;

  FSSL := TLSSLSession.Create(Self);
  FSSL.SSLActive := False;            // make it "off" by default
  FSSL.OnSSLConnect := @OnSSLConnect; // let's watch if TLS/SSL handshake is ok

  FSMTP := TLSMTPClient.Create(Self);
  FSMTP.Session := FSSL;         // set the SSL session, so if it's a SSL/TLS SMTP we can use it
  FSMTP.Timeout := 100;          // responsive enough, but won't hog CPU
  FSMTP.OnReceive := @OnReceive; // assign all events
  FSMTP.OnConnect := @OnConnect;
  FSMTP.OnDisconnect := @OnDisconnect;
  FSMTP.OnError := @OnError;
end;

// Main SMTP processing loop
procedure TLSMTPClientTest.Run;
var
  Addr, Subject, Sender, Recipients, Message: string;
  Port: Integer;
begin
  Addr := '192.168.1.4';                // hard code my mailserver
  Port := 25;                           // hard code my SMTP port number

  Sender := Form1.MailFromEdit.Text;    // get info about email from Form1 edit fields
  Recipients := Form1.MailToEdit.Text;
  Subject := Form1.SubjectEdit.Text;
  Message := Form1.Memo1.Text;

  Form1.Memo2.Append('Connecting to ' + Addr + ':' + IntToStr(Port) + '... ');

  if FSMTP.Connect(Addr, Port) then
    repeat                          // try to connect
        FSMTP.CallAction;           // if initial connect went ok, wait for acknowledgment/otherwise
    until FSMTP.Connected or FQuit; // if quit (eg error), or we connected, then continue

  If(FQuit) then  // if we need to quit because of a connection error
    exit;         // exit now

  while not FQuit do       // do main loop
    begin
      FSMTP.Ehlo;          // "Polite people say HELO first" (yeah, but nearly everyone is enhanced now)
      FSMTP.CallAction;    // main event mechanism, must call periodicly and ASAP, or specify high timeout
      FSMTP.StartTLS;      // ask for TLS
      FSMTP.SendMail(Sender, Recipients, Subject, Message); // send the email
    end;
  end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Button1.Enabled := False;     // disable button until session finished
  Memo2.Clear;                  // clear email log
  SMTP := TLSMTPClientTest.Create(nil);

  Try
    SMTP.Run;                     // try to deliver the mail
  Finally
    SMTP.Free;
    Button1.Enabled := True;      // enable button now session finished
    Memo1.Clear;                  // clear email content
  End;
end;

end.

lazarus lnet smtp client tls.png

Here's a copy of the transaction on the mail server for the above message:

Mar 18 16:22:33 shadow sm-mta[66179]: 221820LG031423: Milter (milter-relay): init success to negotiate
Mar 18 16:22:33 shadow sm-mta[66179]: 221820LG031423: Milter (milter-regex): init success to negotiate
Mar 18 16:22:33 shadow sm-mta[66179]: 221820LG031423: Milter (greylist): init success to negotiate
Mar 18 16:22:33 shadow sm-mta[66179]: 221820LG031423: Milter: connect to filters
Mar 18 16:22:33 shadow sm-mta[66179]: 221820LG031423: STARTTLS=server, relay=macmini8.example.org [192.168.1.21], version=TLSv1.3, verify=NO, cipher=TLS_AES_256_GCM_SHA384, bits=256/256
Mar 18 16:22:34 shadow milter-greylist[25940]: 221820LG031423: addr = macmini8.example.org[192.168.1.21], from = <trev@nowhereonearth.com>, rcpt = <trev@example.org>
Mar 18 16:22:34 shadow milter-greylist[25940]: whitelisted by {greylist}
Mar 18 16:22:34 shadow sm-mta[66179]: 221820LG031423: Subject:Test.email
Mar 18 16:22:34 shadow sm-mta[66179]: 221820LG031423: from=<trev@nowhereonearth.com>, size=73, class=0, nrcpts=1, msgid=<202203180522.22I5MXc3066179@shadow.example.org>, proto=ESMTP, daemon=IPv4, relay=macmini8.example.org [192.168.1.21]
Mar 18 16:22:34 shadow sm-mta[66179]: 221820LG031423: Milter (greylist) add: header: X-Greylist: Message whitelisted by Sendmail access database, not delayed by milter-greylist-4.6.4 (shadow.example.org [192.168.1.4]); Fri, 18 Mar 2022 16:22:34 +1100 (AEDT)
Mar 18 16:22:34 shadow sm-mta[66179]: 221820LG031423: Milter accept: message
Mar 18 16:22:34 shadow sm-mta[66180]: 221820LG031423: to=<trev@example.org>, delay=00:00:00, xdelay=00:00:00, mailer=local, pri=30597, relay=local, dsn=2.0.0, stat=Sent

The full project source code is available for download from SourceForge.

See also

  • lNet
  • Synapse - Email Examples
  • RFC2821 Simple Mail Transfer Protocol (SMTP)
  • RFC3207 SMTP Service Extension for Secure SMTP over Transport Layer Security (TLS)
  • RFC5246 The Transport Layer Security (TLS) Protocol Version 1.2
  • RFC8446 The Transport Layer Security (TLS) Protocol Version 1.3