Transaction Object

An SMTP transaction is valid from MAIL FROM time until RSET or "final-dot".

API

  • transaction.uuid

A unique UUID for this transaction. Is equal to the connection.uuid + '.N' where N increments for each transaction on this connection.

  • transaction.mail_from

The value of the MAIL FROM command as an Address1 object.

  • transaction.rcpt_to

An Array of Address1 objects of recipients from the RCPT TO command.

  • transaction.message_stream

A node.js Readable Stream object for the message.

You use it like this:

transaction.message_stream.pipe(WritableStream, options)

Where WritableStream is a node.js Writable Stream object such as a net.socket, fs.writableStream, process.stdout/stderr or custom stream.

The options argument should be an object that overrides the following properties:

    * line_endings (default: "\r\n")
    * dot_stuffing (default: false)
    * ending_dot   (default: false)
    * end          (default: true)
    * buffer_size  (default: 65535)
    * clamd_style  (default: false)

e.g.

transaction.message_stream.pipe(socket, { dot_stuffing: true, ending_dot: true });
  • transaction.data_bytes

The number of bytes in the email after DATA.

  • transaction.add_data(line)

Adds a line of data to the email. Note this is RAW email - it isn't useful for adding banners to the email.

  • transaction.notes

A safe place to store transaction specific values. See also haraka-results and haraka-notes.

  • transaction.add_leading_header(key, value)

Adds a header to the top of the header list. This should only be used in very specific cases. Most people will want to use add_header() instead.

  • transaction.add_header(key, value)

Adds a header to the email.

  • transaction.remove_header(key)

Deletes a header from the email.

  • transaction.header

The header of the email. See Header Object.

  • transaction.parse_body = true|false default: false

Set to true to enable parsing of the mail body. Make sure you set this in hook_data or before.

  • transaction.body

The body of the email if you set parse_body above. See Body Object.

  • transaction.attachment_hooks(start)

Sets a callback for when we see an attachment if parse_body has been set.

The start event will receive (content_type, filename, body, stream) as parameters.

The stream is a ReadableStream - see http://nodejs.org/api/stream.html for details on how this works.

If you set stream.connection then the stream will apply backpressure to the connection, allowing you to process attachments before the connection has ended. Here is an example which stores attachments in temporary files using the tmp library from npm and tells us the size of the file:

exports.hook_data = function (next, connection) {
    // enable mail body parsing
    connection.transaction.parse_body = true;
    connection.transaction.attachment_hooks(
        function (ct, fn, body, stream) {
            start_att(connection, ct, fn, body, stream)
        }
    );
    next();
}

function start_att (connection, ct, fn, body, stream) {
    connection.loginfo("Got attachment: " + ct + ", " + fn + " for user id: " + connection.transaction.notes.hubdoc_user.email);
    connection.transaction.notes.attachment_count++;

    stream.connection = connection; // Allow backpressure
    stream.pause();

    var tmp = require('tmp');

    tmp.file(function (err, path, fd) {
        connection.loginfo("Got tempfile: " + path + " (" + fd + ")");
        var ws = fs.createWriteStream(path);
        stream.pipe(ws);
        stream.resume();
        ws.on('close', function () {
            connection.loginfo("End of stream reached");
            fs.fstat(fd, function (err, stats) {
                connection.loginfo("Got data of length: " + stats.size);
                // Close the tmp file descriptor
                fs.close(fd, function(){});
            });
        });
    });
}
  • transaction.discard_data = true|false default: false

Set this flag to true to discard all data as it arrives and not store in memory or on disk (in the message_stream property). You can still access the attachments and body if you set parse_body to true. This is useful for systems which do not need the full email, just the attachments or mail text.

  • transaction.set_banner(text, html)

Sets a banner to be added to the end of the email. If the html part is not given (optional) then the text part will have each line ending replaced with <br/> when being inserted into HTML parts.

  • transaction.add_body_filter(ct_match, filter)

Adds a filter to be applied to body parts in the email. ct_match should be a regular expression to match against the full content-type line, or a string to match at the start, e.g. /^text\/html/ or 'text/plain'. filter will be called when each body part matching ct_match is complete. It receives three parameters, the content-type line, the encoding name, and a buffer with the full body part. It should return a buffer with the desired contents of the body in the same encoding.

  • transaction.results

Store results of processing in a structured format. See docs/Results

1: Address objects are address-rfc2821 objects. See https://github.com/haraka/node-address-rfc2821