Skip to content

ZenProjects/phpSMTPd

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

94 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

License: GPL v3


WARNING

The project are completely experimental

At this stage of the project they can only receive SMTP message and store message it on inbound queue...


Pure PHP SMTP Daemon

PHP SMTP daemon are Experimental Project of SMTP server daemon coded 100% in PHP with the PECL-Event extension.

Within this project they have implemented complete SMTP Client and Server stack 100% in PHP completely based on PECL-Event (libevent).

They start as standalone Multiprocess pre-forked server daemon, with a watchdog (using pcntl_fork and pecl-event to manage signal event of the worker).

They start as root (or not) and listen (EventListener) on socket port (can be <1025 if started as root) and impersonate to other user (if started as with use of posix setuid/gid).

The skeleton of the server part are based on SMTP event based example on php site by Andrew Rose : http://php.net/manual/fr/event.examples.php

The STARTTLS server part are from this example also, the client part has been developped from scratch.

The PHP daemon also inspired me. http://daemon.io/

The SMTP Implementation are largely based on D.J. Bernstein (QMAIL) implementation notes: http://cr.yp.to/smtp.html

Links SMTP verbs
http://cr.yp.to/smtp/helo.html HELO, RSET, and NOOP verbs
http://cr.yp.to/smtp/ehlo.html EHLO verb
http://cr.yp.to/smtp/mail.html MAIL, RCPT, and DATA verbs
http://cr.yp.to/smtp/quit.html QUIT verb
http://cr.yp.to/smtp/vrfy.html VRFY/EXPN verbs
http://cr.yp.to/smtp/8bitmime.html 8BITMIME extension
http://cr.yp.to/smtp/size.html SIZE extension

Prerequisit

PHP V5.5 minimum

PHP Extension:

Install and start the daemon

Clone the git to the directory to install:

$ git clone https://github.com/ZenProjects/phpsmtpd.git

Configure the daemon :

$ cd phpsmtpd
$ cp config/php-smtpd.ini.sample to config/php-smtpd.ini

edit config/php-smtpd.ini and change the different parametter needed.

create user for the daemon and change user parametter acordingly.

user = phpsmtpd

create /path/to/queue/basedir change the owner of this directory to "user" parameter.

queue_dir = /path/to/queue/basedir

Activate/desactivate SMTP extension:

xclient = false
xforward = false
tls = false

Prepare hostname.certificat.chained.crt certificate and hostname.privatekey.key private key files.

like in this links:

ssl_server_crt          = /path/to/hostname.certificat.chained.crt
ssl_server_key          = /path/to/hostname.privatekey.key

Start the server:

$ sbin/smtpd --listen --daemon

to see if has started:

$ ps -ef | grep phpSMTP
root      70045  23858  0 02:01 pts/1    00:00:00 phpSMTPdaemon
root      70051  70045  0 02:01 pts/1    00:00:00 phpSMTPdaemon-Worker #0
root      70052  70045  0 02:01 pts/1    00:00:00 phpSMTPdaemon-Worker #1
root      70053  70045  0 02:01 pts/1    00:00:00 phpSMTPdaemon-Worker #2
root      70054  70045  0 02:01 pts/1    00:00:00 phpSMTPdaemon-Worker #3
root      70064  32148  0 02:01 pts/3    00:00:00 grep phpSMTP

Read in your syslog config file where "mail" facilty go.

Example in /etc/rsyslog.conf :

# Log all the mail messages in one place.
mail.*                                                  -/path/to/maillog

And you can see debug information on this maillog:

$ tail -f /path/to/maillog 
Nov  8 02:01:36 hotpoint phpSMTPd[70045]: Starting phpSMTPdaemon Serveur pid:70045 listen:127.0.0.1:2025 at <Sat, 08 Nov 2014 01:01:36 +0000>
Nov  8 02:01:36 hotpoint phpSMTPd[70045]: Using PHP v5.5.10
Nov  8 02:01:36 hotpoint phpSMTPd[70045]: With PECL-Event v1.11.0
Nov  8 02:01:36 hotpoint phpSMTPd[70045]: With OpenSSL 1.0.1e-fips 11 Feb 2013
Nov  8 02:01:36 hotpoint phpSMTPd[70045]: Loaded extensions Core,date,ereg,libxml,pcre,sqlite3,ctype,dba,dom,fileinfo,filter,hash,iconv,json,SPL,PDO,pdo_sqlite,openssl,posix,Reflection,session,SimpleXML,standard,tokenizer,xml,xmlreader,xmlwriter,apcu,curl,sockets,ftp,gd,mailparse,mbstring,mysql,mysqli,zlib,pcntl,pdo_mysql,pdo_pgsql,pgsql,pthreads,shmop,event,sysvmsg,sysvsem,sysvshm,tokyo_tyrant,zip,Phar,zmq,mhash,apc
Nov  8 02:01:36 hotpoint phpSMTPd[70045]: Try to run the daemon
Nov  8 02:01:36 hotpoint phpSMTPd[70045]: CreateQueue... at /opt/phpsmtpd/includes/SMTPDaemon.php:53
Nov  8 02:01:36 hotpoint phpSMTPd[70045]: Run the daemon in listen mode
Nov  8 02:01:36 hotpoint phpSMTPd[70045]: This machine has 4 processing unit
Nov  8 02:01:36 hotpoint phpSMTPd[70045]: This EventProcessPool with 4 workers was created...
Nov  8 02:01:36 hotpoint phpSMTPd[70045]: Init shm /opt/phpsmtpd/ipc/scoreboard at 0xf521ba1f
Nov  8 02:01:36 hotpoint phpSMTPd[70045]: Init sem /opt/phpsmtpd/ipc/scoreboard_sem at 0x4eefbb99
Nov  8 02:01:36 hotpoint phpSMTPd[70045]: QueueCount queue inbound = 178
Nov  8 02:01:36 hotpoint phpSMTPd[70045]: Starting Listening SMTP on 127.0.0.1:2025 at myhost.tld
Nov  8 02:01:36 hotpoint phpSMTPd[70045]: hook <HeartBeat> set to <phpSMTPd\SMTPDaemon::SuperviseQueue>
Nov  8 02:01:36 hotpoint phpSMTPd[70045]: Go in dispatch
Nov  8 02:01:36 hotpoint phpSMTPd[70045]: EventProcessPoolManager start at Sat, 08 Nov 2014 01:01:36 +0000
Nov  8 02:01:36 hotpoint phpSMTPd[70045]: EventProcessPoolManager Worker #0 forked with pid:70051 at Sat, 08 Nov 2014 01:01:36 +0000
Nov  8 02:01:36 hotpoint phpSMTPd[70051]: Worker #0 with pid:70051 started at <Sat, 08 Nov 2014 01:01:36 +0000>
Nov  8 02:01:36 hotpoint phpSMTPd[70045]: EventProcessPoolManager Worker #1 forked with pid:70052 at Sat, 08 Nov 2014 01:01:36 +0000
Nov  8 02:01:36 hotpoint phpSMTPd[70052]: Worker #1 with pid:70052 started at <Sat, 08 Nov 2014 01:01:36 +0000>
Nov  8 02:01:36 hotpoint phpSMTPd[70045]: EventProcessPoolManager Worker #2 forked with pid:70053 at Sat, 08 Nov 2014 01:01:36 +0000
Nov  8 02:01:36 hotpoint phpSMTPd[70053]: Worker #2 with pid:70053 started at <Sat, 08 Nov 2014 01:01:36 +0000>
Nov  8 02:01:36 hotpoint phpSMTPd[70045]: EventProcessPoolManager Worker #3 forked with pid:70054 at Sat, 08 Nov 2014 01:01:36 +0000
Nov  8 02:01:36 hotpoint phpSMTPd[70054]: Worker #3 with pid:70054 started at <Sat, 08 Nov 2014 01:01:36 +0000>

SMTP Implementation Notes

SMTP client

  • Implement client part of SMTP, and implement this SMTP verbs: EHLO/HELO, STARTTLS, XFORWARD, XCLIENT, MAIL FROM, RCPT TO, QUIT
  • no need HELP, SEND, SAML, SOML, TURN, ETRN verbs in this client
  • for the moment no support for VRFY/EXPN, but possible addition to VRFY/EXPN support in future to check address
  • based largely on D.J. Bernstein (author of QMAIL) implementation notes: http://cr.yp.to/smtp/client.html
  • Conform with ESMTP standard RFC 1869 and implement this extension : 8BITMIME, STARTTLS, SIZE, XCLIENT, XFORWARD

Implementation detail:

HELO/EHLO + XFORWARD/XCLIENT + STARTLS verbs

  • EHLO are sent systematicly (as say djb), and HELO only if $this->forceehlo is set to false and the SERVER not responded ESMTP in gretting
  • NOTE: possible amelioration is to send HELO in case of error with EHLO for server that not support ESMTP.
  • abort if SIZE receved form the server are larger than data message
  • send xclient/xforward information if the server support it
  • Transmit all XCLIENT attributs ($this->xclients array, it not set send [UNAVAILABLE]) found in XCLIENT EHLO response...
  • Transmit all XFORWARD attributs ($this->xforwards array, it not set send [UNAVAILABLE]) found in XFORWARD EHLO response...
  • STARTLS if the server claim to support it and the $this->tls attribut is set

MAIL, RCPT and DATA verbs

  • all are implemented
  • not SIZE option on MAIL cmd for the moment...
  • no Q-P conversion (for the moment, but in regard of djb note are not needed anymore...), send 8bit for all server even if the server not specify 8BITMIME in EHLO

QUIT verb

  • send quit, wait response and close connection
  • NOTE: possible amelioration is to not wait response... like qmail client

SMTP Server

  • Implement this SMTP verbs: EHLO/HELO, STARTTLS, XFORWARD, XCLIENT, MAIL, RCPT, RSET, VRFY, NOOP, QUIT
  • no HELP, SEND, SAML, SOML, TURN, ETRN verbs
  • conforming to ESMTP standard RFC 1869 and implement this extension : 8BITMIME, STARTTLS, SIZE, XCLIENT, XFORWARD
  • based largely on D.J. Bernstein (author of QMAIL) implementation notes: http://cr.yp.to/smtp.html

Implementation detail:

HELO/EHLO + XFORWARD/XCLIENT + STARTLS verbs

  • support EHLO and HELO
  • HELO not send extension like EHLO does
  • send extension SIZE (send server configured maximum message size), 8BITMIME, VRFY as default
  • send XCLIENT/XFORWARD extension if configuration enabeled
  • send STARTTLS extension if configuration enabeled
  • check resolvabilty of the hostname sended

MAIL, RCPT and DATA verbs

  • all are implemented
  • MAIL and RCPT controle the address format
  • RCPT controle if the destination are configured Mailling List
  • controle the sequancing the cmds
  • SIZE option on MAIL cmd are supported, and abort if the size is larger the server configured maximum.
  • no Q-P conversion, full 8BITMIME server.

VRFY, NOOP, RSET

  • VRFY controle if the addresse are configured as mailing list
  • NOOP do noop...
  • RSET reset the enveloppe and restart sequencing to after EHLO/HELO

QUIT verb

  • QUIT close the connection after sending bye message

To use/test STARTLS:

  1. Prepare cert.pem certificate and privkey.pem private key files.

    http://rene.bz/setting-smtp-authentication-over-tls-postfix/

    http://www.postfix.org/TLS_README.html

  2. Launch the server script

  3. to test TLS support:

    $ openssl s_client -connect localhost:25 -starttls smtp -crlf -quiet -state -msg

    or

    $ gnutls-cli --crlf --starttls -p 25 --debug 256 --insecure 127.0.0.1

    • send EHLO and STARTTLS

    • and after the response of STARTTLS

    • send CTRL-D and gnutls-cli go in TLS handcheck

You can test also with swaks: http://www.jetmore.org/john/code/swaks/

$ ./swaks --to mylist@listes.mydomain.tld --from myaddresse@mydomain.tld --server 127.0.0.1:25 -tls


The SMTP principal RFCs:

http://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol

http://en.wikipedia.org/wiki/Extended_SMTP

SMTP : RFC 5321 – Simple Mail Transfer Protocol

http://tools.ietf.org/html/rfc5321

ESMTP : RFC 1869 – SMTP Service Extensions

http://tools.ietf.org/html/rfc1869

Mail Message Format : RFC 5322 - Internet Message Format

http://tools.ietf.org/html/rfc5322

Requirements for Internet Hosts -- Application and Support

https://tools.ietf.org/html/rfc1123#page-48

SMTP Extension RFC Description
SIZE 1870 SMTP Service Extension for Message Size Declaration
8BITMIME 6152 SMTP Service Extension for 8-bit MIME Transport
STARTTLS 3207 SMTP Service Extension for Secure SMTP over Transport Layer Security
AUTH 4954 SMTP Service Extension for Authentication
PIPELINING 2920 SMTP Service Extension for Command Pipelining
CHUNKING 3030 SMTP Service Extensions for Transmission of Large and Binary MIME Messages
DSN 3461 Simple Mail Transfer Protocol (SMTP) Service Extension for Delivery Status Notifications (DSNs)
ENHANCEDSTATUSCODES 3463 Enhanced Mail System Status Codes
SMTPUTF8 6531 SMTP Extension for Internationalized Email

ESMTP Extension implementation status: