nodemailer / smtp-server

Create custom SMTP servers on the fly
Other
846 stars 145 forks source link

Allow custom object in session per transaction #169

Closed noam7700 closed 2 years ago

noam7700 commented 2 years ago

Allow to maintain custom object in session per transaction.

For example, my use case is that at onMailFrom and onRcptTo steps I dont only validate, but fetches custom info on mailFrom & rcptTo that needs to be used at onData step (where I actually send the mail to our system). More specifically I fetch IDs for them (and by that, validating the mailboxes exist), and I want to use the IDs, and dont refetch them at onData.

I've seen the library maintains envelope object per transaction (reset it at _resetSession etc etc).

Im not sure how the library should allow my use case. I suggest couple of options:

  1. users should manually add custom session properties at onMailFrom step and onRcptTo step (+reseting the properties at onMailFrom , because it's the first command of the session). Can be broken if internal implementation changes, should be supported and documented formally. This is my current workaround. Example code:
    new SMTPServer({
    onMailFrom: () = async (address, session, callback) => {
    session.customData = { fromID: null, rcptToIDs: [] }; // init custom session data (also from previous transactions)
    try {
      const fromID = await getUserIdByAddress(address);
      session.customData = { ...session.customData, fromID }; // add fromID to the custom session data
      callback();
    } catch (err) {
      callback(err);
    }
    },
    onRcptTo: async (address, session, callback) => {
    try {
      const toID = await getUserIdByAddress(address);
      session.customData.rcptToIDs.push(toID); // add toID to the custom session data
      callback();
    } catch (err) {
      callback(err);
    }
    },
    onData: async (stream, session, callback) => {
    const { fromID, rcptToIDs } = session.customData; // use the custom session data
    // ...
    },
    });
  2. allow only custom data that go along with mailFrom & rcptTo, given by passing data at onMailFrom and onRcptTo steps by calling callback(null, {customData}). Similar to the previous but a lot cleaner with proper API. Also, will go along the existing feature to remove duplicates of rcptTo. Maybe will be included at the Address object with customData property.
  3. allow functions to handle generic custom session data. with onCustomSessionDataInit/onTransactionInit, session.getCustomSessionData(), session.setCustomSessionData() .
andris9 commented 2 years ago

You could use WeakMap objects for this where session is the map key.

const sessions = new WeakMap();
…
// on MAIL FROM
sessions.set(session, { values })
….
// on RCPT TO
let sessData = sessions.get(session);
sessData.prop = 1234;