RealRaven2000 / FiltaQuilla

Adds many new mail filter actions to Thunderbird
http://quickfilters.quickfolders.org/filtaquilla.html
GNU General Public License v3.0
85 stars 15 forks source link

JavaScript Search Term Questions #184

Open RealRaven2000 opened 1 year ago

RealRaven2000 commented 1 year ago

Question from a user

I have been using FiltaQuilla for several years now. Mostly I use Javascript in Message Filter Rules.

It is extremely hard to find information about the environment in which the JavaScript code in a message filter rule is being executed.

I was hoping you could point me to some resources that document this.

Here is an example of a filter rule that compares a string of regex expressions to the email SUBJECT

The script assumes the per-existence of the message object. After some time I figured out there was a Mime2DecodedSubject property of the message object that returned a clean string from the email subject.

Likewise, I figured out I could get date or dateReceived properties from the getProperty method of message like this

let emailDate = message.getProperty('dateReceived')

Is there someplace that documents the message object in great detail?

For example, Even though I am able to access the dateReceived property, sending it to console with .toString() produces some HEX value that I have no idea how to convert into a JavaScript date-type. I was hoping this kind of information could be found somewhere. I have scoured the internet with multiple search engines and can only seem to find dated code snippets posted in years gone by which is how I've got things to work as much as I have so far.

Other questions:

dmcichy commented 1 year ago

Question from a user

I have been using FiltaQuilla for several years now. Mostly I use Javascript in Message Filter Rules.

It is extremely hard to find information about the environment in which the JavaScript code in a message filter rule is being executed.

I was hoping you could point me to some resources that document this.

Here is an example of a filter rule that compares a string of regex expressions to the email SUBJECT

The script assumes the per-existence of the message object. After some time I figured out there was a Mime2DecodedSubject property of the message object that returned a clean string from the email subject.

Likewise, I figured out I could get date or dateReceived properties from the getProperty method of message like this

let emailDate = message.getProperty('dateReceived')

Is there someplace that documents the message object in great detail?

For example, Even though I am able to access the dateReceived property, sending it to console with .toString() produces some HEX value that I have no idea how to convert into a JavaScript date-type. I was hoping this kind of information could be found somewhere. I have scoured the internet with multiple search engines and can only seem to find dated code snippets posted in years gone by which is how I've got things to work as much as I have so far.

Other questions:

  • (1) What other objects like message are available within JavaScript and where are they documented?
  • (2) How would you go about getting the message BODY into a string? I have failed miserably at this.

Thanks for posting this on my behalf Alex. Hoping others have knowledge about how to exploit the capabilites of Javascript filter rules and understand it and its environment better than me

dmcichy commented 1 year ago

Here is an example of one of my working javascript filter scripts. This one gets the MIME DECODED Subject from each email. Then I use a string of subject patterns I want to match with regular expressions and test each email's subject. I this example, I am looking for emails that are BILLS from anyone so I can auto file them. The script needs to return a boolean true or false indicating whether or not the regex expression was a match to the subject

/*
FILTER ON "SUBJECT"
===================
LOOK FOR ANY OF THE KEYWORDS IN THE REGEX EXPRESSION AND SELECT ALL MESSAGES CONTAINING THOSE KEYWORDS
*/
function b64DecodeUnicode(str) 
{
  //remove any whitespace characters from the string
  str= str.replace(/\s/g, '');

  // Going backwards: from bytestream, to percent-encoding, to original string.
  return decodeURIComponent(
    atob(str).split('')
    .map(
          function(c) 
          {
              return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
          }
        ).join('')
  );
}

let logOutput=true;
let MimeDecodedSubject = message.mime2DecodedSubject.toString();
let encodedSubject = message.getStringProperty('subject');  // not used because the subject can be MIME Base64 encoded or encoded a thousand other ways
try {if (logOutput) {console.log('getStringProperty(subject)='+encodedSubject);}} catch (e) {console.log('getStringProperty(subject) Failed: '+e)}
let isEncoded=false;
let alwaysDecode=false;

try {if (logOutput) {console.log('Base64 Decode='+b64DecodeUnicode(encodedSubject));}} catch (e) {console.log('Base64Decode Failed: '+e)}

    if (encodedSubject.includes('=?utf-8?') || alwaysDecode)
    {
                isEncoded=true;
        // Get the email SUBJECT which could be encoded as UTF-8.  If it is, then decode it
        encodedSubject = encodedSubject.replace('=?utf-8?B?','')
        try { 
          let decodedSubject=b64DecodeUnicode(encodedSubject)
                  if (logOutput) {console.log('Manually Decoded Subject='+decodedSubject);}
        } 
        catch (e) { 
                  if (logOutput) {console.log('Manually Decode of Subject FAILED with ['+e+']');}
        }
    }

if (logOutput) {console.log('Javascript Filter Condition Checking For Keywords in email SUBJECT property -> '+MimeDecodedSubject );}

let keywordString='bill is.*[available|ready]|bill notification|e-bill|bill pay|online bill'

const Regex = new RegExp(keywordString, 'gi'); //global case insensitive
let MatchesSubject1 = Regex.test(MimeDecodedSubject);
let MatchesSubject2 = Regex.test(encodedSubject);
if (logOutput) {console.log('>>> Keyword Match on MIME Subject ->'+MatchesSubject1.toString());}
if (logOutput && isEncoded) {console.log('>>> Keyword Match on Base64 Decoded Subject ->'+MatchesSubject2.toString());}

MatchesSubject1 || (isEncoded && MatchesSubject2)  // return the result of the regex subject tests
RealRaven2000 commented 1 year ago

Thanks for the example - by the way - you can edit your posts directly on github and apply syntax highlighting using the buttons there:

image

(I edited your previous comments for legibility).

I understand you use the JavaScript search term in order to add as condition for subsequent actions, is this correct?

the match function passes in the variable message which is of type nsIMsgDBHdr .

All members / functions are defined here:

https://searchfox.org/comm-central/source/mailnews/base/public/nsIMsgHdr.idl#14

I am not sure if you can debug code in an eval statement but you might try adding a "debugger;" line to your code to see whether it is possible - to get started, attach the web development debugger in Thunderbird to the main code using Ctrl+Shift+I, set a breakpoint in filtaquilla.js in the object self.javascript inside the match() function.

dmcichy commented 1 year ago

Ok, so I finally figure out how to get the RECEIVED DATE from an email that is being processed by a message-filter-javascript-action and convert that into a value that can be used in javascript to compare to something like the current date-time. My reason for this is that I needed to be able to allow certain emails (by subject and sender) to REMAIN in the INBOX for a certain number of days before allowing the message filter to AUTO-FILE the email into a sub folder

Here is the javascript:

/* Get the received date of the message variable passed into the filter action.  
This is the date the email was received.  This property returns a hex string which represents the 
number of seconds elapsed since Jan 1, 1970 until NOW in whatever timezone the email was received 
*/
let emailDateReceived = message.getProperty('date');  // this property gets returned as a HEX value

// This converts the email DATE property value from HEX STRING to an integer
let RealEmailDateInSeconds = parseInt(emailDateReceived.toString(), 16)  

// Now convert elapsed time of email in seconds since Jan 1 1970 from seconds to milliseconds so it is compatible with Javascript datetime
let RealEmailDateInMilliSeconds = RealEmailDateInSeconds * 1000; 

// Create a javascript variable of type DATE that is equal to the email's received date by passing in milliseconds elapsed
var emailDate= new Date(RealEmailDateInMilliSeconds); 

// get todays date (NOW) as the number of milliseconds that have passed since Jan 1, 1970
var nowDate = new Date(); 
var todaysDateInMilliseconds=nowDate.getTime(); // getTime() returns milliseconds elapsed since  Jan 1, 1970

// Now, calculate how many milliseconds in the number of days you want to delay taking action on an email (in my case the number of days before I have the message filter auto-file the email into a folder
let emailMillisecondsDelay = 0
let DelayDays = 3

emailMillisecondsDelay = delayDays*24*3600*1000;

//If the delay time has elapsed since receiving this email, then is is ready to be auto-filed
let timeExpired = false;
let calculatedTimeDelay = todaysDateInMilliseconds - RealEmailDateInMilliSeconds
if ( calculatedTimeDelay  > emailMillisecondsDelay ) 
{ 
     timeExpired = true; 
}

timeExpired; // Returns boolean value of timeExpired from filter action: true or false
joh6nn commented 1 year ago

I'm successfully using this answer from SO in v102.11.0 to get the message body into a string in a Javascript Action (not a search term). Don't know if that's helpful to you, @dmcichy. Note my comment on the answer about needing to update the line for accessing elements of msgHdrs