@@ -51,6 +51,13 @@ const ENHANCED_STATUS_CODES = {
5151 556 : '5.1.10' // RCPT TO syntax error
5252} ;
5353
54+ // Skip enhanced status codes for initial greeting and HELO/EHLO responses
55+ const SKIPPED_COMMANDS_FOR_ENHANCED_STATUS_CODES = new Set ( [
56+ 'HELO' ,
57+ 'EHLO' ,
58+ 'LHLO'
59+ ] ) ;
60+
5461// Context-specific enhanced status code mappings
5562const CONTEXTUAL_STATUS_CODES = {
5663 // Mail transaction specific codes
@@ -192,7 +199,7 @@ class SMTPConnection extends EventEmitter {
192199 this . _setListeners ( ( ) => {
193200 // Check that connection limit is not exceeded
194201 if ( this . _server . options . maxClients && this . _server . connections . size > this . _server . options . maxClients ) {
195- return this . send ( 421 , this . name + ' Too many connected clients, try again in a moment' ) ;
202+ return this . send ( 421 , this . name + ' Too many connected clients, try again in a moment' , false ) ;
196203 }
197204
198205 // Keep a small delay for detecting early talkers
@@ -255,7 +262,7 @@ class SMTPConnection extends EventEmitter {
255262 ) ;
256263
257264 if ( err ) {
258- this . send ( err . responseCode || 554 , err . message ) ;
265+ this . send ( err . responseCode || 554 , err . message , false ) ;
259266 return this . close ( ) ;
260267 }
261268
@@ -271,7 +278,8 @@ class SMTPConnection extends EventEmitter {
271278 this . name +
272279 ' ' +
273280 ( this . _server . options . lmtp ? 'LMTP' : 'ESMTP' ) +
274- ( this . _server . options . banner ? ' ' + this . _server . options . banner : '' )
281+ ( this . _server . options . banner ? ' ' + this . _server . options . banner : '' ) ,
282+ false
275283 ) ;
276284
277285 if ( typeof next === 'function' ) {
@@ -330,7 +338,7 @@ class SMTPConnection extends EventEmitter {
330338 *
331339 * @param {Number } code Response code
332340 * @param {String|Array } data If data is Array, send a multi-line response
333- * @param {String } context Optional context for enhanced status codes
341+ * @param {String|Boolean } context Optional context for enhanced status codes
334342 */
335343 send ( code , data , context ) {
336344 let payload ;
@@ -531,17 +539,17 @@ class SMTPConnection extends EventEmitter {
531539
532540 // If server already closing then ignore commands
533541 if ( this . _server . _closeTimeout ) {
534- return this . send ( 421 , 'Server shutting down' ) ;
542+ return this . send ( 421 , 'Server shutting down' , commandName ) ;
535543 }
536544
537545 if ( ! this . _ready ) {
538546 // block spammers that send payloads before server greeting
539- return this . send ( 421 , this . name + ' You talk too soon' ) ;
547+ return this . send ( 421 , this . name + ' You talk too soon' , commandName ) ;
540548 }
541549
542550 // block malicious web pages that try to make SMTP calls from an AJAX request
543551 if ( / ^ ( O P T I O N S | G E T | H E A D | P O S T | P U T | D E L E T E | T R A C E | C O N N E C T ) \/ .* H T T P \/ \d \. \d $ / i. test ( command ) ) {
544- return this . send ( 421 , 'HTTP requests not allowed' ) ;
552+ return this . send ( 421 , 'HTTP requests not allowed' , commandName ) ;
545553 }
546554
547555 if ( this . _upgrading ) {
@@ -566,7 +574,7 @@ class SMTPConnection extends EventEmitter {
566574 switch ( commandName ) {
567575 case 'HELO' :
568576 case 'EHLO' :
569- this . send ( 500 , 'Error: ' + commandName + ' not allowed in LMTP server' ) ;
577+ this . send ( 500 , 'Error: ' + commandName + ' not allowed in LMTP server' , false ) ;
570578 return setImmediate ( callback ) ;
571579 case 'LHLO' :
572580 commandName = 'EHLO' ;
@@ -582,10 +590,10 @@ class SMTPConnection extends EventEmitter {
582590 // if the user makes more
583591 this . _unrecognizedCommands ++ ;
584592 if ( this . _unrecognizedCommands >= 10 ) {
585- return this . send ( 421 , 'Error: too many unrecognized commands' ) ;
593+ return this . send ( 421 , 'Error: too many unrecognized commands' , commandName ) ;
586594 }
587595
588- this . send ( 500 , 'Error: command not recognized' ) ;
596+ this . send ( 500 , 'Error: command not recognized' , commandName ) ;
589597 return setImmediate ( callback ) ;
590598 }
591599
@@ -599,7 +607,7 @@ class SMTPConnection extends EventEmitter {
599607 ) {
600608 this . _unauthenticatedCommands ++ ;
601609 if ( this . _unauthenticatedCommands >= this . _maxAllowedUnauthenticatedCommands ) {
602- return this . send ( 421 , 'Error: too many unauthenticated commands' ) ;
610+ return this . send ( 421 , 'Error: too many unauthenticated commands' , commandName ) ;
603611 }
604612 }
605613
@@ -642,22 +650,24 @@ class SMTPConnection extends EventEmitter {
642650 /**
643651 * Gets the appropriate enhanced status code for a given SMTP response code and context
644652 * @param {Number } code SMTP response code
645- * @param {String } context Optional context for more specific status codes
653+ * @param {String|Boolean } context Optional context for more specific status codes
646654 * @returns {String } Enhanced status code or empty string if not applicable
647655 */
648656 _getEnhancedStatusCode ( code , context ) {
649- if ( ! this . _useEnhancedStatusCodes ( ) ) {
657+ if ( context === false || ! this . _useEnhancedStatusCodes ( ) ) {
650658 return '' ;
651659 }
652660
653- // Skip enhanced status codes for initial greeting and HELO/EHLO responses
654- // This is handled by checking the context in the calling code
655-
656661 // Skip 3xx responses as per RFC 2034
657662 if ( code >= 300 && code < 400 ) {
658663 return '' ;
659664 }
660665
666+ // Skip enhanced status codes for initial greeting and HELO/EHLO responses
667+ if ( context && SKIPPED_COMMANDS_FOR_ENHANCED_STATUS_CODES . has ( context ) ) {
668+ return '' ;
669+ }
670+
661671 // Use contextual codes if available
662672 if ( context && CONTEXTUAL_STATUS_CODES [ context ] ) {
663673 return CONTEXTUAL_STATUS_CODES [ context ] ;
@@ -831,7 +841,7 @@ class SMTPConnection extends EventEmitter {
831841 let hostname = parts [ 1 ] || '' ;
832842
833843 if ( parts . length !== 2 ) {
834- this . send ( 501 , 'Error: syntax: ' + ( this . _server . options . lmtp ? 'LHLO' : 'EHLO' ) + ' hostname' ) ;
844+ this . send ( 501 , 'Error: syntax: ' + ( this . _server . options . lmtp ? 'LHLO' : 'EHLO' ) + ' hostname' , false ) ;
835845 return callback ( ) ;
836846 }
837847
@@ -862,7 +872,7 @@ class SMTPConnection extends EventEmitter {
862872 }
863873
864874 this . _resetSession ( ) ; // EHLO is effectively the same as RSET
865- this . send ( 250 , [ this . name + ' Nice to meet you, ' + this . clientHostname ] . concat ( features || [ ] ) ) ;
875+ this . send ( 250 , [ this . name + ' Nice to meet you, ' + this . clientHostname ] . concat ( features || [ ] ) , false ) ;
866876
867877 callback ( ) ;
868878 }
@@ -875,14 +885,14 @@ class SMTPConnection extends EventEmitter {
875885 let hostname = parts [ 1 ] || '' ;
876886
877887 if ( parts . length !== 2 ) {
878- this . send ( 501 , 'Error: Syntax: HELO hostname' ) ;
888+ this . send ( 501 , 'Error: Syntax: HELO hostname' , false ) ;
879889 return callback ( ) ;
880890 }
881891
882892 this . hostNameAppearsAs = hostname . toLowerCase ( ) ;
883893
884894 this . _resetSession ( ) ; // HELO is effectively the same as RSET
885- this . send ( 250 , this . name + ' Nice to meet you, ' + this . clientHostname ) ;
895+ this . send ( 250 , this . name + ' Nice to meet you, ' + this . clientHostname , false ) ;
886896
887897 callback ( ) ;
888898 }
0 commit comments