Lotus Notes attachment using Perl

Hi all,
i would like to use perl script (not satisfied with Lotus notes scripting) to store attachments from mail database within assigned folder (like C:\MAIL), not overwriting attachment with the same name and finally deleting the attachment or whole email from mail database.
Is there anybody who could help me?
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

lebenoAuthor Commented:
I have seen these scripts and tested, but there is no deletion added. Due to fact my perl skills are really poor, I'm not able to modify that.
Get your problem seen by more experts

Be seen. Boost your question’s priority for more expert views and faster solutions

To delete attachments from document use this on each doc:


If your perl is poor why didn't you cross-post to Perl zone?

Wait a minute, you said you're "not satisfied with Lotus notes scripting" and the you choose to use perl, for which you said you don't have skills?

OK, lets put this right, tell me what are you good at, and I'll help you do that in the language of your choice.
lebenoAuthor Commented:
I'm fine with DOS scripting or vbs. I would love lotus notes scripting also, but ended on lack of permissions at LN server, where I couldn't schedule the agent.
This perl script would give me what I need, it's just one time issue.
and this is what I could modified form the origin script :
use strict;
use English;
use warnings;
use vars qw($opt_d $opt_v);
use charnames ':full';
use Getopt::Std;
use Win32::OLE;
use Win32;

# Command-line options:
# -d dirname    Save everything under the directory "dirname"
# -v            Verbose reporting of progress

# Define a directory to store the results
my $dir = $opt_d || Win32::GetFolderPath(Win32::CSIDL_PERSONAL) . '\\Notes2Files';
my $Counter = 1;

# Define a list of "Normal" folders to skip
my @badlist = ('Sent', 'Archiving\\Age of Documents',
               'Discussion Threads', 'Events', 'All by Purge Date', 'Stationery');

# Auto-print carriage returns

# Open the email database in Lotus Notes
# (To use another person's email database, switch to
#  their userid in Notes before running this program)
my $notes = Win32::OLE->new('Notes.NotesSession')
             or die "Can't open Lotus Notes";
my $database = $notes->GetDatabase("","");

# Verify the server connection
print "Connected to ", $database->{Title},
      " on ", $database->{Server} if $opt_v;

# Loop over all of the folders
foreach my $viewname (GetViews($database)) {

  # Get the object for this View
  print "Saving Messages in folder $viewname...";
  my $view = $database->GetView($viewname);

  # Create a subdirectory to store the messages in
  $viewname =~ tr/()$//d;
  $viewname =~ s(\\)(.)g;

 my $path = 'D:\Archives';
  mkdir ($path, 0755)
      or die "Can't make directory $path: $!";
  chdir ($path);

  # Get the first document in the folder
  my $num = 1;
  my $doc = $view->GetFirstDocument;
  next unless $doc;
  GetInfo($num, $path, $doc);

  # Get the remaining documents in the folder
  while ($doc = $view->GetNextDocument($doc)) {
    GetInfo($num, $path, $doc);

sub GetInfo {
  my ($num, $path, $doc) = @_;

print "Processing message $num";

if ( $doc->HasEmbedded ) {
      my $DocumentBody = $doc->GetFirstItem('Body');

      foreach my $embeddedDoc ( $DocumentBody->{EmbeddedObjects} ) {
         foreach my $arryele ( @{$embeddedDoc } ) {
           my @array = $arryele->{Source};
           ExtractAttachment($doc, "$path", @array);

sub ExtractAttachment {
 my ($doc, $path, $filename) = @_;
 $Counter = $Counter + 1;
 #Get a Windows-friendly pathname for the file
  $path = "$path/$Counter-$filename";
  $path =~ tr/\//\\/;

print "Extracting attachment $path";

  # Save the attachment to a file
  my $attachment = $doc->GetAttachment($filename);
  eval { $attachment->ExtractFile($path);
     print("Error Saving Attachment:$filename:$?:$!:$@:$^E\n");
#$doc->RemoveItem("$filename") or die ("Unable to remove\n");

sub GetViews {
  my ($database) = @_;
  my @views = ();

  # Loop through all of the views in this database
  my $array_ref = $database->{Views};
  foreach my $view (@$array_ref) {
    my $name = $view->{Name};

    # We only want folders if it's the Inbox or Sent
    # or a normal folder name with no parentheses
    if ( ($name =~ "TRANSFER"))
      # Add the folder name to the @views list
      # if it's not in the @badlist
      push(@views, $name) unless (grep { $name eq $_ } @badlist);

  return @views;
could u correct it 4me?
But you'll have the same access problem no matter which programming language you use.

This perl script is simply using Lotus exposed OLE classes.
Sjef BosmanGroupware ConsultantCommented:
And if you want to delete an attachment you need write permission in the user's database. Since the attachment is inside a mail document, and you remove the attachment, you have to save the document which requires write permission.

In what database is this? Is it some action you want to run every x minutes, on specific mails (I don't read Poil), to fetch incoming attachments?
lebenoAuthor Commented:
i have the manager rights on this mail file as I could see it at ACL. To delete whole email with embedded attachment is also fine. There is no necessity to keep the body without attachment.
what is the purpose... there are random incoming emails with attachment (simple plain text files). I need to download these attachment and to upload to oracle database. Emails keep fixed subject suffix REPORT_DB_timestamp, the same as the name of attachment.  I've created the rule in mailbox to forward these mails to assigned folder ('cause I didn't know how to add dedicated view into perl script, or how to filter emails according subject), in the script it's TRANSFER.
At this moment I'm able to download the attachments (can run every 5 mins) - this is running fine  but have to avoid downloading the same attach. more times.
Sjef BosmanGroupware ConsultantCommented:
Why don't you forward the whole mail to the Oracle environment? I assume Oracle can receive mails...
lebenoAuthor Commented:
i have only the experience with sending emails from ora, but opposite direction?? could be a way..let's do some research
Sjef BosmanGroupware ConsultantCommented:
I have no knowledge of Oracle systems whatsoever, but this seems a reasonably clear document:
Whether it can be applied to your situation...?
The easiest solution here would be to have a mail triggered agent in Lotus db that detaches attachment to a specified network location.
On the other side, in Oracle, you can do two different things, either set up:
    - SOA approach:   web service that would be called by Lotus agent (to signal new attachment arrival)
    - old school:          stored procedure that would run on schedule and check the network location for files
Sjef BosmanGroupware ConsultantCommented:
I assume the asker is trying to avoid Lotus programming...
Same here, but it then turned out that he avoided it because he thought that security could be bypassed by using perl.
Sjef BosmanGroupware ConsultantCommented:
So maybe he can still avoid it by doing everything from Oracle. If Oracle can somehow receive and handle mails... Seems this is one more advantage of Domino over Oracle! ;-)
lebenoAuthor Commented:
To be honest, LN agent would be better solution 'cause no need to have LN client opened while detaching attachment, for perl script it's mandatory. I have modified LN agent found in e-e site which was working fine but only using manual start, not scheduled via time frame or action (after new mail arrival).  I deemed the problem could be the scheduled agent run at server side and therefore ln server didn't have the permissions to my folder destination.
I'm afraid with Oracle it could more complicated, but any way is acceptable.
Sjef BosmanGroupware ConsultantCommented:
I agree that an agent is probably best. A scheduled agent always runs on the server, so you would have to use an open server directory to save the attachment, e.g. a Temp directory.
lebenoAuthor Commented:
and this is my problem " to get such a server directory, our 2nd level LN admins are not willing to cooperate.
Next idea could to be to use the current perl script with a small correction : change the prefix of the file name ($path = "$path/$Counter-$filename") - not to use counter but someting like xxx_ so my sqlloader would ignore duplicates.
to have more options is better then nothing:)
Sjef BosmanGroupware ConsultantCommented:
Not willing to cooperate?? How dare they?! Send them a mail, CC to your boss, explaining in detail what you want (e.g. a private temp. directory on the server), and ask them their formal reply. If you're not satisfied, send your request to your boss, CC them, and walk the hierarchy, up to the CIO if need be. Admins like that drive me insane! They think they're there to protect their realm instead of helping their colleagues.

It is the Notes agent that's not allowed to save a file on the file system? Well, ask them to sign the agent, or demand a full explanation why they don't want it.
I don't understand your last comment, the directory doesn't have to be on the Domino server file system, any shared network folder will do.
Tell them you'll give them the code yourself, what a hell, right :)
Sjef BosmanGroupware ConsultantCommented:
AFAIK Marko, a restricted agent can't write files at all... I suppose that's the real problem here.
I was commenting this sentence:
and this is my problem " to get such a server directory, our 2nd level LN admins are not willing to cooperate.

And you're right Sjef, of course, but why wouldn't we allow that agent to run restricted operations (agent properties), we already have to change its code, don't we (folder path)?
lebenoAuthor Commented:
Company hierarchy is not usable, I'm representative of subsidiary, and CIO hates me...
I have used common widows share, but ln agent works only with manual start therefore I deemed it has to be Domino share. I have also tried different agent settings without success.
I will provide u the ln agent on Thue, maybe I do something wrong.
First you need to do is change agent property "Set runtime agent security" to "Allow restricted operations".
Post the code, of course...
Sjef BosmanGroupware ConsultantCommented:
Maybe he's not allowed to run restricted agents, as configured in the Security section of the Server document. Next, I'd love to see your code, because maybe it isn't correct for a background agent (for instance, there should not be a NotesUIWorkspace).

Finally, if the Admins are a PITA, and his CIO hates his guts, I see only one real alternative: get the hell out of there. Stuff them!

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
lebenoAuthor Commented:
Here is the ln agent used :
Sub Initialize
      Dim session As New NotesSession
      Dim db As NotesDatabase
      Dim object As NotesEmbeddedObject
      Dim collection As NotesDocumentCollection
      Dim doc As NotesDocument
      Dim downloadfolder As String
      Set db = session.CurrentDatabase
      Set collection = db.UnprocessedDocuments
      downloadfolder = "\\\ln\users\"
      'If Dir("\\\ln",16)="" Then Mkdir "\\\ln"
      If Dir("\\\ln\users",16)="" Then Mkdir "\\\ln\users"
      Print "************************************************************************"
      For i = 1 To collection.Count
            Set doc = collection.GetNthDocument( i )
            antalfiler=Evaluate("@Attachments", doc)
            If Dir("\\\ln\users\"+username,16)="" Then Mkdir "\\\ln\users\"+username
            Print Str(i)+" ("+Str(collection.count)+")"
            If antalfiler(0)>0 Then
                  For filecounter=0 To antalfiler(0)-1
                        Print ( filen(filecounter))
                        Set Object = doc.GetAttachment( filen(filecounter) )
                        If ( object.Type = EMBED_ATTACHMENT ) Then
                              fileCount = fileCount + 1
                              If Dir(downloadfolder+username+"\"+ filen(filecounter))="" Then
                                    extrachar=Left(doc.universalid,4)+"---" 'in case attachmnet with same name exists in several documents
                              End If
                              Call object.ExtractFile (downloadfolder+"\"+username+"\"+extrachar+ filen(filecounter) )
' Call object.Remove 'delete the attachment from document
' Call doc.Save( True, False )
                        End If
                  Next filecounter
            End If
      'Msgbox"Attachments: "+Str(fileCount )
End Sub

Settings : scheduled to run every 5 mins
       Runtime level : 2.Allow restricted operations
ACL : User type : Person
         Access : Manager
   Attributes enabled : Create documents, Delete Documents, Create private agents, Create personal folders/views, Create shared folders/views, Create LotusScript/JAVA agents, Read public documents, Write public documents, Replicate or copy documents
At a first glance the code looks fine.
What happens when you run it?
You can temporarily make the agent triggered by action (not schedule) so you can test it.

Are you allowed to run restricted agents on your server (see Sjef's last comment)?
Sjef BosmanGroupware ConsultantCommented:
Are there any error messages in the log.nsf database, under Miscellaneous?

What could be clever in the meantime is to add some error catching code.

At the start, add the line
      On Error Goto oops

At the end, before the End Sub, add the lines

      Exit Sub
      MsgBox "Error on line " & Erl & ": " & Error$
      Resume exitsub

Wait till the modified agent has run once, and check the log database if there's an error in it.
lebenoAuthor Commented:
There are no errors in log.nsf, I had just issue with encypted mail content. I've checked Domino directory and it's bad :       
Sign or run restricted LotusScript/Java agents:      $Admin.FirstClass
it is the same in all items. I'm not in the right group. So it looks like I can only thank you both for excellent support many times and whimper ln admins...Am I wrong?
You're right, you'd have to be in that group in order to run unrestricted agents on that server.
lebenoAuthor Commented:
OK,I'm going to fight for my rights:)
Could u just help me to modify the agent to run only for dedicated view?
The problem is not related to views, saving files to file system is considered to be a restricted operation by Lotus, so that is your problem, you cannot manipulate file system from your agent.
lebenoAuthor Commented:
I'm aware of that now, I just wanted to modify the agent before I start the dealing with ln admins for case that they will refuse my request and I will be force to ask to sign the agent by them.
On the other hand when I run Agent test, I get this message :

The following will occur when this agent is run:

'CN=username/OU=GDSK/O=GuD' has unrestricted rights to run LotusScript/Java agents on 'CN=servername/OU=SRV/O=GuD'.
Allow restricted operations flag is selected. Restriction operations will be allowed.
Agent scheduled to run on 'CN=servername/OU=SRV/O=GuD'.
AFAICS, that means that you were given the rights to run unrestricted agents on that server.

I don't understand what's wrong with them signing the agent?
lebenoAuthor Commented:
There two points :
- there is difference between Domino directory and the agent test result. Is that fine?
- that was just an idea to sign the agent in case of lack of rights, but due to first point I'm quite confused where the problem is
To change the agent scope simply make it run on "All documents in a view", as opposed to "All documents in a database".
Also change the trigger: On event - Action menu selection.

Then turn debugger on, open your database and run the agent using Actions menu.

Use step-into to execute code line by line.
lebenoAuthor Commented:
our ln admins has signed my agent and the result is : Agent will not run, scheduled to run on 'CN=NOTES....
This is other story.
Thank u both gentlemen for excelent and quick support.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Lotus IBM

From novice to tech pro — start learning today.