java.lang.Object
i2p.susi.webmail.smtp.SMTPClient

public class SMTPClientextends Object
SMTP client for sending email through SMTP servers over I2P. Supports command pipelining, attachments, and size limits optimized for I2P. Includes base64 size calculations and 8BITMIME support for efficient I2P mail delivery.
  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    private static class 
    A result string and code.
    private static class 
    A command to send and a result code to expect.
  • Field Summary

    Modifier and Type
    Field
    Description
    private final Log
    Logger for this class.
    private static final Encoding
    Encoder for base64-authenticated logins.
    static final long
    7629902 ~= 7.27 MB Base64 encodes 57 chars to 76 + \r\n on a line.
    static final long
    10.00 MB smtp.postman.i2p as of 2024-06-22.
    Error message from the last failed operation, or empty if none.
    private String
    The server's reply to the last command.
    private long
    Largest message the server accepts, in bytes.
    private Socket
    Socket connection to the SMTP server.
    private boolean
    True if the server accepts 8-bit message bodies.
    private boolean
    True if the server accepts pipelined commands.
  • Constructor Summary

    Constructors
    Constructor
    Description
    Creates a client with no error.
  • Method Summary

    Modifier and Type
    Method
    Description
    private static String
    Looks up a localized string in the message bundle.
    private static String
    _t(String s, Object o)
    Looks up a localized string in the message bundle, substituting one parameter.
    (package private) static String
    capsText(boolean pipelining, long maxSize, boolean eightBitMime)
    Reports what the server's EHLO response allowed, so a reader can tell why a message was refused on size or sent without pipelining.
    Read the complete server reply.
    private int
    The numeric code of the last server reply.
    private int
    Writes a command to the server and waits for its reply.
    private int
    sendCmd(String cmd, boolean shouldWait)
    Writes a command to the server, optionally without waiting for the reply.
    private int
    sendCmd(String cmd, boolean shouldWait, boolean mask)
    Writes a command to the server, optionally without waiting for the reply and optionally masked in the debug log.
    private void
    Does not flush, wait, or read.
    private void
    sendCmdNoWait(String cmd, boolean mask)
    Does not flush, wait, or read.
    private int
    Sends the commands back to back if the server supports pipelining, otherwise one at a time.
    boolean
    sendMail(String host, int port, String user, String pass, String sender, List<String> recipients, StringBuilder body, List<Attachment> attachments, String boundary)
    Sends one message to an SMTP server, authenticating first when a user name is given.
    static void
    writeMail(Writer out, StringBuilder body, List<Attachment> attachments, String boundary)
    Caller must close out.

    Methods inherited from class Object

    clone, equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Field Details

    • DEFAULT_MAX_SIZE

      public static final long DEFAULT_MAX_SIZE
      10.00 MB smtp.postman.i2p as of 2024-06-22.
      See Also:
    • BINARY_MAX_SIZE

      public static final long BINARY_MAX_SIZE
      7629902 ~= 7.27 MB Base64 encodes 57 chars to 76 + \r\n on a line.
      See Also:
    • _log

      private final Log _log
      Logger for this class.
    • socket

      private Socket socket
      Socket connection to the SMTP server.
    • error

      public String error
      Error message from the last failed operation, or empty if none.
    • lastResponse

      private String lastResponse
      The server's reply to the last command.
    • supportsPipelining

      private boolean supportsPipelining
      True if the server accepts pipelined commands.
    • supports8BitMime

      private boolean supports8BitMime
      True if the server accepts 8-bit message bodies.
    • maxSize

      private long maxSize
      Largest message the server accepts, in bytes.
    • base64

      private static final Encoding base64
      Encoder for base64-authenticated logins.
  • Constructor Details

    • SMTPClient

      public SMTPClient()
      Creates a client with no error.
  • Method Details

    • sendCmd

      private int sendCmd(String cmd)
      Writes a command to the server and waits for its reply.
      Parameters:
      cmd - the command to write, or null to send nothing
      Returns:
      result code or 0 for failure
    • sendCmd

      private int sendCmd(String cmd, boolean shouldWait)
      Writes a command to the server, optionally without waiting for the reply.
      Parameters:
      cmd - the command to write, or null to send nothing
      shouldWait - if false, don't wait for response, and return 100
      Returns:
      result code or 0 for failure
    • sendCmd

      private int sendCmd(String cmd, boolean shouldWait, boolean mask)
      Writes a command to the server, optionally without waiting for the reply and optionally masked in the debug log.
      Parameters:
      cmd - the command to write, or null to send nothing
      shouldWait - if false, don't wait for response, and return 100
      mask - true to mask the command in debug logs (credentials)
      Returns:
      result code or 0 for failure
    • sendCmdNoWait

      private void sendCmdNoWait(String cmd) throws IOException
      Does not flush, wait, or read.
      Parameters:
      cmd - the command to write, never null
      Throws:
      IOException - if there is no connected socket, or the write fails
    • sendCmdNoWait

      private void sendCmdNoWait(String cmd, boolean mask) throws IOException
      Does not flush, wait, or read.
      Parameters:
      cmd - the command to write, never null
      mask - true to mask the command in debug logs (credentials)
      Throws:
      IOException - if there is no connected socket, or the write fails
    • capsText

      static String capsText(boolean pipelining, long maxSize, boolean eightBitMime)
      Reports what the server's EHLO response allowed, so a reader can tell why a message was refused on size or sent without pipelining. Each capability is answered yes or no rather than left as a bare phrase, and the wire name is kept beside the prose so the line stays greppable.
      Parameters:
      pipelining - whether the server accepts pipelined commands
      maxSize - the message size limit the server reported, in bytes
      eightBitMime - whether the server accepts unencoded 8-bit bodies
      Returns:
      the multi-line log message
    • sendCmds

      private int sendCmds(List<SMTPClient.SendExpect> cmds)
      Sends the commands back to back if the server supports pipelining, otherwise one at a time.
      Parameters:
      cmds - the commands to send in order, never null or empty
      Returns:
      number of successful commands
    • getResult

      private int getResult()
      The numeric code of the last server reply.
      Returns:
      result code or 0 for failure
    • getFullResult

      private SMTPClient.Result getFullResult()
      Read the complete server reply.
      Returns:
      result code and string, all lines combined with \r separators, first 3 bytes are the ASCII return code or "000" for failure Result and Result.recv non null
    • sendMail

      public boolean sendMail(String host, int port, String user, String pass, String sender, List<String> recipients, StringBuilder body, List<Attachment> attachments, String boundary)
      Sends one message to an SMTP server, authenticating first when a user name is given. Any failure is appended to the error field rather than thrown.
      Parameters:
      host - the SMTP server to connect to
      port - the SMTP server port to connect to
      user - the AUTH LOGIN user name, base64-encoded on the wire
      pass - the AUTH LOGIN password, base64-encoded on the wire
      sender - the envelope sender, sent as MAIL FROM
      recipients - the envelope recipients, sent as one RCPT TO each
      body - headers and body, without the attachments
      attachments - may be null
      boundary - non-null if attachments is non-null
      Returns:
      true if the server accepted the message, false if any step failed
    • writeMail

      public static void writeMail(Writer out, StringBuilder body, List<Attachment> attachments, String boundary) throws IOException
      Caller must close out.
      Parameters:
      out - the writer that receives the message, left open for the caller
      body - headers and body, without the attachments
      attachments - may be null
      boundary - non-null if attachments is non-null
      Throws:
      IOException - if the socket write or the attachment encoding fails
    • _t

      private static String _t(String s)
      Looks up a localized string in the message bundle.
      Parameters:
      s - the English text used as the lookup key
      Returns:
      the translation for the current language, or s itself when untranslated
    • _t

      private static String _t(String s, Object o)
      Looks up a localized string in the message bundle, substituting one parameter.
      Parameters:
      s - the English text used as the lookup key, with {0} where the value goes
      o - substituted for {0} in the message
      Returns:
      the translation for the current language, or s itself when untranslated