How to use specific value extracted from the file in the name?

#1 : 03/07-25 19:24
Chris
Posts: 38
I need to add to the filenames of many EML files the value of the Date: field within each file, e.g.

myfile.EML (containing Date: Mon, 30 Jul 2012 14:00:10 +0200)

to

myfile Mon, 30 Jul 2012 14_00_10 +0200.EML

Can Advanced Renamer do this?

Neither <File Content :pos:count:filename> nor <File Line:x> suffices given the position is variable. I can see no way to get scripting to read the file content (but will ask separately about that).

Or (less likely I guess) any way specifically to add an EML's Date. Note that Windows property ItemDate is inaccurate - failing to include zone.

Thanks.

EDIT: Script solution here: https://www.advancedrenamer.com/forum_thread/script-to-prepe nd-eml-date-16051

edited: 07/07-25 10:52
#2 : 03/07-25 23:29
Delta Foxtrot
Posts: 521
Reply to #1:

Hi Chris,

As a standard written in the early 1980s, rfc822 is something of a mess. The last update was around 2001, so good luck there... A decade before iPhone. And we seem to be stuck with the spaghetti-code of formats, since organizations need to be able to read emails sent from the 80s on.

That said, I found some .eml files on my system and every one had the date in the first line of the header. (They all are from the same email app though). If you are that lucky it won't be hard to extract the date using 1) a new name method comprised of "<Name>_<File line:1>"; then 2) various replace methods to strip unnecessary characters and format the date. It took me four methods, three replace and a list replace, to do it on my emails.

With a different header setup you'll need a script to get there. Do you have coding, especially javascript, experience? If not you'll probably need some help doing what you need.

I'd need to see sample email headers to see if I have the skills to get what you need. It might be as simple as reading header lines using "app.parseTags('File Line:'+n+'>')" in a loop to find the date, but I won't know without seeing what you are working with.

Or maybe Kim will have some other suggestion; as the creator of Advanced Renamer he's really the go-to guy for file format questions.

Using my .eml files, this script pulled the date and added it to the filename:

// -----------------------------------------------------
oldName = item.newBasename;
dateStack = app.parseTags( '<File Line:1>' ) ;
pattern = /(\d{4})(\d{2})(\d{2}) (\d{6})\.\d+ms (.*)/ ;
if ( pattern.test( dateStack ) ) {
newName = oldName + "_" + dateStack.replace( pattern, "$1-$2-$3 $4-$5" ) ;
}
pattern = /Date ([A-Za-z]{3}), (\d{1,2}) ([A-Za-z]{3}) (\d{4}) (\d{6}) .\d{4} \(([A-Z]+)\)/ ;
if ( pattern.test( dateStack ) ) {
newName = oldName + "_" + dateStack.replace( pattern, "$4-$3-$2 $5-$6" ) ;
}
return newName ;
// -----------------------------------------------------

(Minus converting Jan/Feb/Mar etc to numbers, which is nothing really).
EDIT: This is just a script version of the 4 methods I used to pull the date without a script. END EDIT

Adding a loop to query header lines *might* be all that's necessary to convert this to your format, but again, I won't know without seeing your header format(s).

Best,
DF

edited: 03/07-25 23:47
#3 : 04/07-25 09:05
Delta Foxtrot
Posts: 521
Reply to #2:

Chris,

Try this script, see if it does what you need. Let me know.

// --------------------------------------------------
oldName = item.newBasename;
for ( j = 1; j < 9; j++ ) {
line = app.parseTags( '<File Line:'+j+'>' ) ;
if ( line.slice(0,4) == "Date" ) {
firstSpace = line.indexOf( " " ) ;
// process date:
d = line.slice( firstSpace )
d1 = d.replace( /(\d{2})(\d{2})(\d{2})/, "$1_$2_$3" ) ;
return oldName + d1 ;
}
}
return oldName;
// --------------------------------------------------

Best,
DF
#4 : 04/07-25 11:25
Chris
Posts: 38
> As a standard written in the early 1980s, rfc822 is something of a mess. The last update was around 2001, so good luck there...

Understood, but IME Date: is probably the most reliable of all the header fields, so I doubt much luck is required. And since Windows can parse it fine (for System.ItemDate) that it can't be too hard! :)

> I found some .eml files on my system and every one had the date in the first line of the header.

They must be sent-form messages. Received-form messages never do, IME. I recommend https://datatracker.ietf.org/doc/html/rfc822#appendix-A.3.3

Hence my "<File Line:x> suffices given the position is variable".

> various replace methods to strip unnecessary characters

I know of no unnecessary characters. I do know of unacceptable characters e.g. : , which I would replace.

> It might be as simple as reading header lines using "app.parseTags('File Line:'+n+'>')" in a loop to find the date

Ah, I think it would! Date: must appear once and only once in the header, so scanning for the first would suffice for all compliant messages. To cover nbon-complaint messages, ideally abort and report fail upon reaching the header end.

> Do you have coding, especially javascript, experience?

Yes.

> If not you'll probably need some help doing what you need.

That too! :)

> I'd need to see sample email headers to see if I have the skills to get what you need.

https://github.com/isbg/isbg/blob/master/tests/examples/spam .eml

Thanks!

> (Minus converting Jan/Feb/Mar etc to numbers, which is nothing really).

There should be no conversion of the header field except replacement of disallowed chars.



#5 : 04/07-25 13:38
Chris
Posts: 38
Reply to #3:

Thanks. The script failed on that example, due to j<9. Fixed:

// --------------------------------------------------
oldName = item.newBasename;
for ( j = 1; ; j++ ) {
line = app.parseTags( '<File Line:'+j+'>' ) ;
if(line =='') return "Error: no Date: found";
if ( line.slice(0,4) == "Date" ) {
firstSpace = line.indexOf( " " ) ;
// process date:
d = line.slice( firstSpace )
return oldName + d;
}
}
// --------------------------------------------------

Result: https://i.imgur.com/yvftoBm.png

Note: if(line =='') is risky since it relies on undefined behaviour of "app.parseTags(tags): string Parses the specified string for tags and returns the result." (User Guide).

I found "d1 = " did nothing so removed it. Perhaps it was intended to replace ':'. I find AN is out-of-script replacing ':' by '-', which I'll accept.

I'm uncomfortable with "firstSpace = line.indexOf( " " ) ; " requirement for a pre-value space since I see none allowed or required by the spec https://datatracker.ietf.org/doc/html/rfc822#page-9 . I will recode to make it optional and excluded.

I changed the field name matcher to include the RFC-required ':'.

if ( line.slice(0,5) == "Date:" ) {

but this failed to match. Any idea why? EDIT: This bug: https://www.advancedrenamer.com/forum_thread?forum_id=16012


edited: 04/07-25 19:52
#6 : 04/07-25 21:56
Delta Foxtrot
Posts: 521
Reply to #5:

Hi Chris,

My main point was to demonstrate how you can loop through the lines of a text file using the app.parseTags() command in ARen. I didn't expect perfect results immediately. :)

For some reason I can't access imgur (ever, apparently) so I'm blind in this conversation, but here's another, hopefully helpful, hint. ARen is short on script-debugging tools, but there is app.log() which is like console.log except it outputs to the "js console" (menu item "Tools / JS Console"). I like to let the script return the original filename and get debugging info in the console, but that's just me.

I used a space as my cut-off point in that script because some headers I found didn't include a colon, and it doesn't matter anyway since the file line has to start with "Date" which should be specific enough.

Oh, btw, the "d1" transform was only there to insert underscores in the time portion like you indicated in your first message. Totally unnecessary to the logic.

Best,
DF
#7 : 05/07-25 12:46
Chris
Posts: 38
Reply to #6:
> there is app.log() which is like console.log except it outputs to the "js console" (menu item "Tools / JS Console").

Thanks. I'd tried that console but could not get it to accept input. It seems to me it is not a console. Juts an output window.

> I like to let the script return the original filename and get debugging info in the console

I'd like that too, except here (Windows 7) the "console" is a modal window that prevents me running the script.

> I used a space as my cut-off point in that script because some headers I found didn't include a colon

I've never seen that egregious non-compliance so thanks for that warning! I

> it doesn't matter anyway since the file line has to start with "Date" which should be specific enough.

I'm avoiding relying on that since it invites a fail on future format update.


> Oh, btw, the "d1" transform was only there to insert underscores in the time portion

Thanks, but it wasn't succeeding. The regex appears faulty.


#8 : 05/07-25 21:08
Kim Jensen
Administrator
Posts: 1002
Reply to #2:
DF I think your method is good. I have no better way to accomplish this. I don't know how standard the date formatting is. They may be formatted in many various ways, which just makes the script more complex. If the Date isn't located on the first line of the file, this won't work well.

Extracting data from the files in the batch is not very pretty, and usually doesn't work. In most cases it is needed to parse some part of the file to isolate the needed value. I prefer to implement native support for various file types instead.
#9 : 05/07-25 22:17
Delta Foxtrot
Posts: 521
Reply to #8:

Hi Kim, Chris,

This isn't particularly pretty but it seems to work, and avoids leaving the second parameter of the for loop empty, which I don't think is a good idea.

n = item.newBasename ;
for ( j = 1; app.parseTags( "<file line:"+j+">" ) != ""; j++ ) {
line = app.parseTags( " <file line:"+j+">" ) ;
// app.log( index + " - " + line ) ; // document what's happening
if ( /^ ?date/i.test( line ) ) {
return n + " " + line.replace(/^ ?date ?/i, "" ) ;
}
}
return n ; // only here to illustrate that if no date returns original filename

EDIT: 1) I commented out the app.log line.
2) Could use this method to pull other information of course.
3) You'll probably have to edit these lines:

if ( /^ ?date/i.test( line ) ) {
return n + " " + line.replace(/^ ?date ?/i, "" ) ;

to use whatever character you have in that unsupported character field in settings. I have a space, so that's what I used. OR set your ARen to use a space, or nothing.
END EDIT

Best,
DF

edited: 06/07-25 00:31
#10 : 06/07-25 18:53
Chris
Posts: 38
Reply to #9:

Thanks.

> f ( /^ ?date/i.test( line ) ) {

Note: that accepts date whereas the spec requires Date.

return n + " " + line.replace(/^ ?date ?/i, "" ) ;

> that unsupported character field in settings.

That is not operating as documented (reported here https://www.advancedrenamer.com/forum_thread/bug-tag-file-li ne-replaces-colon-with-dash-16012)
#11 : 06/07-25 20:05
Delta Foxtrot
Posts: 521
Reply to #10:

>> f ( /^ ?date/i.test( line ) ) {
>Note: that accepts date whereas the spec requires Date.

Yes. I made that decision, consciously, and you as a coder are free to do something else. It works as written with my limited set of example files, but if I find later that it's a hindrance I can always adjust.

>> return n + " " + line.replace(/^ ?date ?/i, "" ) ;
> that unsupported character field in settings.

So change it if you find it offensive, or if it doesn't work on your files. What's the big damage?

You do you brother.
#12 : 06/07-25 23:20
Chris
Posts: 38
Reply to #11:

I don't find it offensive. Just pointing out the issue to anyone else who might be unhappy should the AR behaviour/docs discrepancy be remedied and their code break.
#13 : 07/07-25 05:18
Delta Foxtrot
Posts: 521
Reply to #12:

That sounds fair. :)