@upyo/smtp 0.6.0-dev.299 → 0.6.0-dev.303

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -563,6 +563,37 @@ var SmtpPipelineTerminatedError = class extends Error {
563
563
  }
564
564
  };
565
565
  /**
566
+ * An authentication failure backed by an SMTP server reply.
567
+ *
568
+ * This keeps {@link SmtpAuthError} as the public authentication error while
569
+ * retaining the reply fields needed to build structured transport receipts.
570
+ *
571
+ * @since 0.6.0
572
+ */
573
+ var SmtpAuthResponseError = class extends SmtpAuthError {
574
+ /** The numeric SMTP reply code returned by the server. */
575
+ code;
576
+ /** The authentication command that produced the reply. */
577
+ command;
578
+ /** The textual SMTP reply returned by the server. */
579
+ response;
580
+ /**
581
+ * Creates an authentication response error.
582
+ *
583
+ * @param message A human-readable description of the authentication failure.
584
+ * @param code The numeric SMTP reply code.
585
+ * @param command The authentication command that produced the reply.
586
+ * @param response The textual SMTP reply returned by the server.
587
+ */
588
+ constructor(message, code, command, response) {
589
+ super(message);
590
+ this.name = "SmtpAuthResponseError";
591
+ this.code = code;
592
+ this.command = command;
593
+ this.response = response;
594
+ }
595
+ };
596
+ /**
566
597
  * The maximum length of an SMTP command line, including the terminating CRLF,
567
598
  * as specified by RFC 5321 §4.5.3.1.4.
568
599
  */
@@ -866,11 +897,11 @@ var SmtpConnection = class {
866
897
  const response = await this.sendCommand(`EHLO ${this.config.localName}`, signal);
867
898
  if (response.code === 500 || response.code === 502) {
868
899
  const heloResponse = await this.sendCommand(`HELO ${this.config.localName}`, signal);
869
- if (heloResponse.code !== 250) throw new Error(`HELO failed: ${heloResponse.message}`);
900
+ if (heloResponse.code !== 250) throw new SmtpResponseError(`HELO failed: ${heloResponse.message}`, heloResponse.code, "HELO", heloResponse.message);
870
901
  this.capabilities = [];
871
902
  return;
872
903
  }
873
- if (response.code !== 250) throw new Error(`EHLO failed: ${response.message}`);
904
+ if (response.code !== 250) throw new SmtpResponseError(`EHLO failed: ${response.message}`, response.code, "EHLO", response.message);
874
905
  this.capabilities = response.raw.split("\r\n").filter((line) => line.startsWith("250-") || line.startsWith("250 ")).slice(1).map((line) => line.substring(4)).filter((line) => line.length > 0);
875
906
  }
876
907
  async starttls(signal) {
@@ -878,7 +909,7 @@ var SmtpConnection = class {
878
909
  if (this.socket instanceof node_tls.TLSSocket) throw new Error("Connection is already using TLS");
879
910
  signal?.throwIfAborted();
880
911
  const response = await this.sendCommand("STARTTLS", signal);
881
- if (response.code !== 220) throw new Error(`STARTTLS failed: ${response.message}`);
912
+ if (response.code !== 220) throw new SmtpResponseError(`STARTTLS failed: ${response.message}`, response.code, "STARTTLS", response.message);
882
913
  signal?.throwIfAborted();
883
914
  return new Promise((resolve, reject) => {
884
915
  const timeout = setTimeout(() => {
@@ -951,16 +982,16 @@ var SmtpConnection = class {
951
982
  const { user, pass } = auth;
952
983
  const credentials = btoa(`\0${user}\0${pass}`);
953
984
  const response = await this.sendCommand(`AUTH PLAIN ${credentials}`, signal);
954
- if (response.code !== 235) throw new Error(`Authentication failed: ${response.message}`);
985
+ if (response.code !== 235) throw new SmtpAuthResponseError(`Authentication failed: ${response.message}`, response.code, "AUTH PLAIN", response.message);
955
986
  }
956
987
  async authLogin(auth, signal) {
957
988
  const { user, pass } = auth;
958
989
  let response = await this.sendCommand("AUTH LOGIN", signal);
959
- if (response.code !== 334) throw new Error(`AUTH LOGIN failed: ${response.message}`);
990
+ if (response.code !== 334) throw new SmtpAuthResponseError(`AUTH LOGIN failed: ${response.message}`, response.code, "AUTH LOGIN", response.message);
960
991
  response = await this.sendCommand(btoa(user), signal);
961
- if (response.code !== 334) throw new Error(`Username authentication failed: ${response.message}`);
992
+ if (response.code !== 334) throw new SmtpAuthResponseError(`Username authentication failed: ${response.message}`, response.code, "AUTH LOGIN", response.message);
962
993
  response = await this.sendCommand(btoa(pass), signal);
963
- if (response.code !== 235) throw new Error(`Password authentication failed: ${response.message}`);
994
+ if (response.code !== 235) throw new SmtpAuthResponseError(`Password authentication failed: ${response.message}`, response.code, "AUTH LOGIN", response.message);
964
995
  }
965
996
  /**
966
997
  * Resolves an OAuth 2.0 access token via the connection's token manager,
@@ -1012,16 +1043,19 @@ var SmtpConnection = class {
1012
1043
  async finishOAuth2(response, mechanism, continuation, signal) {
1013
1044
  if (response.code === 235) return;
1014
1045
  if (response.code === 334) {
1046
+ let finalResponse;
1015
1047
  let finalMessage = "";
1016
1048
  try {
1017
- const final = await this.sendCommand(continuation, signal);
1018
- finalMessage = ` (${final.message})`;
1049
+ finalResponse = await this.sendCommand(continuation, signal);
1050
+ finalMessage = ` (${finalResponse.message})`;
1019
1051
  } catch {
1020
1052
  signal?.throwIfAborted();
1021
1053
  }
1022
- throw new SmtpAuthError(`${mechanism} authentication failed: ${decodeOAuth2Challenge(response.message)}${finalMessage}`);
1054
+ const message = `${mechanism} authentication failed: ${decodeOAuth2Challenge(response.message)}${finalMessage}`;
1055
+ if (finalResponse != null) throw new SmtpAuthResponseError(message, finalResponse.code, `AUTH ${mechanism}`, finalResponse.message);
1056
+ throw new SmtpAuthError(message);
1023
1057
  }
1024
- throw new SmtpAuthError(`${mechanism} authentication failed: ${response.message}`);
1058
+ throw new SmtpAuthResponseError(`${mechanism} authentication failed: ${response.message}`, response.code, `AUTH ${mechanism}`, response.message);
1025
1059
  }
1026
1060
  async sendMessage(message, signal) {
1027
1061
  signal?.throwIfAborted();
@@ -1949,7 +1983,7 @@ var SmtpTransport = class {
1949
1983
  await connection.connect(signal);
1950
1984
  signal?.throwIfAborted();
1951
1985
  const greeting = await connection.greeting(signal);
1952
- if (greeting.code !== 220) throw new Error(`Server greeting failed: ${greeting.message}`);
1986
+ if (greeting.code !== 220) throw new SmtpResponseError(`Server greeting failed: ${greeting.message}`, greeting.code, "GREETING", greeting.message);
1953
1987
  signal?.throwIfAborted();
1954
1988
  await connection.ehlo(signal);
1955
1989
  signal?.throwIfAborted();
@@ -2049,7 +2083,7 @@ function createSmtpFailure(message, error) {
2049
2083
  attempts: 1,
2050
2084
  providerDetails: { missingCapability: error.missingCapability }
2051
2085
  });
2052
- if (error instanceof SmtpResponseError) {
2086
+ if (error instanceof SmtpResponseError || error instanceof SmtpAuthResponseError) {
2053
2087
  const enhancedStatusCode = parseEnhancedSmtpStatusCode(error.code, error.response);
2054
2088
  const classification = classifySmtpReply(error.code, enhancedStatusCode);
2055
2089
  return (0, __upyo_core.createFailedReceipt)(message, {
@@ -2061,7 +2095,7 @@ function createSmtpFailure(message, error) {
2061
2095
  providerDetails: {
2062
2096
  command: error.command,
2063
2097
  response: error.response,
2064
- rejectedRecipients: error.rejectedRecipients,
2098
+ rejectedRecipients: error instanceof SmtpResponseError ? error.rejectedRecipients : void 0,
2065
2099
  ...enhancedStatusCode == null ? {} : { enhancedStatusCode }
2066
2100
  }
2067
2101
  });
package/dist/index.js CHANGED
@@ -540,6 +540,37 @@ var SmtpPipelineTerminatedError = class extends Error {
540
540
  }
541
541
  };
542
542
  /**
543
+ * An authentication failure backed by an SMTP server reply.
544
+ *
545
+ * This keeps {@link SmtpAuthError} as the public authentication error while
546
+ * retaining the reply fields needed to build structured transport receipts.
547
+ *
548
+ * @since 0.6.0
549
+ */
550
+ var SmtpAuthResponseError = class extends SmtpAuthError {
551
+ /** The numeric SMTP reply code returned by the server. */
552
+ code;
553
+ /** The authentication command that produced the reply. */
554
+ command;
555
+ /** The textual SMTP reply returned by the server. */
556
+ response;
557
+ /**
558
+ * Creates an authentication response error.
559
+ *
560
+ * @param message A human-readable description of the authentication failure.
561
+ * @param code The numeric SMTP reply code.
562
+ * @param command The authentication command that produced the reply.
563
+ * @param response The textual SMTP reply returned by the server.
564
+ */
565
+ constructor(message, code, command, response) {
566
+ super(message);
567
+ this.name = "SmtpAuthResponseError";
568
+ this.code = code;
569
+ this.command = command;
570
+ this.response = response;
571
+ }
572
+ };
573
+ /**
543
574
  * The maximum length of an SMTP command line, including the terminating CRLF,
544
575
  * as specified by RFC 5321 §4.5.3.1.4.
545
576
  */
@@ -843,11 +874,11 @@ var SmtpConnection = class {
843
874
  const response = await this.sendCommand(`EHLO ${this.config.localName}`, signal);
844
875
  if (response.code === 500 || response.code === 502) {
845
876
  const heloResponse = await this.sendCommand(`HELO ${this.config.localName}`, signal);
846
- if (heloResponse.code !== 250) throw new Error(`HELO failed: ${heloResponse.message}`);
877
+ if (heloResponse.code !== 250) throw new SmtpResponseError(`HELO failed: ${heloResponse.message}`, heloResponse.code, "HELO", heloResponse.message);
847
878
  this.capabilities = [];
848
879
  return;
849
880
  }
850
- if (response.code !== 250) throw new Error(`EHLO failed: ${response.message}`);
881
+ if (response.code !== 250) throw new SmtpResponseError(`EHLO failed: ${response.message}`, response.code, "EHLO", response.message);
851
882
  this.capabilities = response.raw.split("\r\n").filter((line) => line.startsWith("250-") || line.startsWith("250 ")).slice(1).map((line) => line.substring(4)).filter((line) => line.length > 0);
852
883
  }
853
884
  async starttls(signal) {
@@ -855,7 +886,7 @@ var SmtpConnection = class {
855
886
  if (this.socket instanceof TLSSocket) throw new Error("Connection is already using TLS");
856
887
  signal?.throwIfAborted();
857
888
  const response = await this.sendCommand("STARTTLS", signal);
858
- if (response.code !== 220) throw new Error(`STARTTLS failed: ${response.message}`);
889
+ if (response.code !== 220) throw new SmtpResponseError(`STARTTLS failed: ${response.message}`, response.code, "STARTTLS", response.message);
859
890
  signal?.throwIfAborted();
860
891
  return new Promise((resolve, reject) => {
861
892
  const timeout = setTimeout(() => {
@@ -928,16 +959,16 @@ var SmtpConnection = class {
928
959
  const { user, pass } = auth;
929
960
  const credentials = btoa(`\0${user}\0${pass}`);
930
961
  const response = await this.sendCommand(`AUTH PLAIN ${credentials}`, signal);
931
- if (response.code !== 235) throw new Error(`Authentication failed: ${response.message}`);
962
+ if (response.code !== 235) throw new SmtpAuthResponseError(`Authentication failed: ${response.message}`, response.code, "AUTH PLAIN", response.message);
932
963
  }
933
964
  async authLogin(auth, signal) {
934
965
  const { user, pass } = auth;
935
966
  let response = await this.sendCommand("AUTH LOGIN", signal);
936
- if (response.code !== 334) throw new Error(`AUTH LOGIN failed: ${response.message}`);
967
+ if (response.code !== 334) throw new SmtpAuthResponseError(`AUTH LOGIN failed: ${response.message}`, response.code, "AUTH LOGIN", response.message);
937
968
  response = await this.sendCommand(btoa(user), signal);
938
- if (response.code !== 334) throw new Error(`Username authentication failed: ${response.message}`);
969
+ if (response.code !== 334) throw new SmtpAuthResponseError(`Username authentication failed: ${response.message}`, response.code, "AUTH LOGIN", response.message);
939
970
  response = await this.sendCommand(btoa(pass), signal);
940
- if (response.code !== 235) throw new Error(`Password authentication failed: ${response.message}`);
971
+ if (response.code !== 235) throw new SmtpAuthResponseError(`Password authentication failed: ${response.message}`, response.code, "AUTH LOGIN", response.message);
941
972
  }
942
973
  /**
943
974
  * Resolves an OAuth 2.0 access token via the connection's token manager,
@@ -989,16 +1020,19 @@ var SmtpConnection = class {
989
1020
  async finishOAuth2(response, mechanism, continuation, signal) {
990
1021
  if (response.code === 235) return;
991
1022
  if (response.code === 334) {
1023
+ let finalResponse;
992
1024
  let finalMessage = "";
993
1025
  try {
994
- const final = await this.sendCommand(continuation, signal);
995
- finalMessage = ` (${final.message})`;
1026
+ finalResponse = await this.sendCommand(continuation, signal);
1027
+ finalMessage = ` (${finalResponse.message})`;
996
1028
  } catch {
997
1029
  signal?.throwIfAborted();
998
1030
  }
999
- throw new SmtpAuthError(`${mechanism} authentication failed: ${decodeOAuth2Challenge(response.message)}${finalMessage}`);
1031
+ const message = `${mechanism} authentication failed: ${decodeOAuth2Challenge(response.message)}${finalMessage}`;
1032
+ if (finalResponse != null) throw new SmtpAuthResponseError(message, finalResponse.code, `AUTH ${mechanism}`, finalResponse.message);
1033
+ throw new SmtpAuthError(message);
1000
1034
  }
1001
- throw new SmtpAuthError(`${mechanism} authentication failed: ${response.message}`);
1035
+ throw new SmtpAuthResponseError(`${mechanism} authentication failed: ${response.message}`, response.code, `AUTH ${mechanism}`, response.message);
1002
1036
  }
1003
1037
  async sendMessage(message, signal) {
1004
1038
  signal?.throwIfAborted();
@@ -1926,7 +1960,7 @@ var SmtpTransport = class {
1926
1960
  await connection.connect(signal);
1927
1961
  signal?.throwIfAborted();
1928
1962
  const greeting = await connection.greeting(signal);
1929
- if (greeting.code !== 220) throw new Error(`Server greeting failed: ${greeting.message}`);
1963
+ if (greeting.code !== 220) throw new SmtpResponseError(`Server greeting failed: ${greeting.message}`, greeting.code, "GREETING", greeting.message);
1930
1964
  signal?.throwIfAborted();
1931
1965
  await connection.ehlo(signal);
1932
1966
  signal?.throwIfAborted();
@@ -2026,7 +2060,7 @@ function createSmtpFailure(message, error) {
2026
2060
  attempts: 1,
2027
2061
  providerDetails: { missingCapability: error.missingCapability }
2028
2062
  });
2029
- if (error instanceof SmtpResponseError) {
2063
+ if (error instanceof SmtpResponseError || error instanceof SmtpAuthResponseError) {
2030
2064
  const enhancedStatusCode = parseEnhancedSmtpStatusCode(error.code, error.response);
2031
2065
  const classification = classifySmtpReply(error.code, enhancedStatusCode);
2032
2066
  return createFailedReceipt(message, {
@@ -2038,7 +2072,7 @@ function createSmtpFailure(message, error) {
2038
2072
  providerDetails: {
2039
2073
  command: error.command,
2040
2074
  response: error.response,
2041
- rejectedRecipients: error.rejectedRecipients,
2075
+ rejectedRecipients: error instanceof SmtpResponseError ? error.rejectedRecipients : void 0,
2042
2076
  ...enhancedStatusCode == null ? {} : { enhancedStatusCode }
2043
2077
  }
2044
2078
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@upyo/smtp",
3
- "version": "0.6.0-dev.299",
3
+ "version": "0.6.0-dev.303",
4
4
  "description": "SMTP transport for Upyo email library",
5
5
  "keywords": [
6
6
  "email",
@@ -53,7 +53,7 @@
53
53
  },
54
54
  "sideEffects": false,
55
55
  "peerDependencies": {
56
- "@upyo/core": "0.6.0-dev.299+9e97f9f2"
56
+ "@upyo/core": "0.6.0-dev.303+d776cb0f"
57
57
  },
58
58
  "devDependencies": {
59
59
  "tsdown": "^0.12.7",