How can I get the date of an email using Perl's Mail::MboxParser::Mail? - perl

This is a simple question. I have a little program here that reads
a list of emails in a specific inbox of a user account specified by the program.
I can access an account using its username, password and host. The only problem is I don't know how to get the date on each of these mails.
Here's some part of my code:
my $pop = new Mail::POP3Client(
USER => $user, #some user,password & host assigned
PASSWORD => $pass,
HOST => $host );
for( $i = 1; $i <= $pop->Count(); $i++ ) {
#header = $pop->Head($i);
#body = $pop->Body($i);
$mail = new Mail::MboxParser::Mail(\#header, \#body);
$user_email = $mail->from()->{email
print "Email:".$user_email; #this prints out right
foreach( $pop->Head( $i ) ) {
/^(Date):\s+/i && print $_, "\n";
$date = $_;
}
}
Now what i need is to get the only one date for each email,
but that loop gives me all.. but when remove the loop, it
returns an error. I'm using Perl.
Kindly help me? :)

According to MboxParser::Email doc, you should be able to do:
$date = $mail->header->{'date'}; #Keys are all lowercase
If you have more than one date returned, $date will be an array ref and you can access the first occurence of the Date with:
$date->[0];
So you shouldn't need to loop through the header and use a regular expression.

Related

perl LDAP entry not recognised

We are writing a Perl code (to be run from Unix) which will reset the password of a Windows AD User. (We are not using powershell as we have been asked not to use Windows scripts).
With the following Perl code, we are able to connect to the AD User directory and query the correct user.
#!/usr/bin/perl -w
#########################
#This script resets the password in active user directory
#########################
use strict;
use warnings;
use DBI;
use Net::LDAP;
use Net::LDAPS;
use Authen::SASL qw(Perl);
use Net::LDAP::Control::Paged;
use Time::Local;
my $CERTDIR = "<cert path>";
my $AD_PASS = "$CERTDIR/.VDIAD_pass";
my $sAN = "vahmed";
### Generate Random Password ###
my $randompass = askPasswd();
my $uninewpass;
my $mail;
my $fullname;
my $name;
my $distName;
my $finalresult;
my #AD_passwords = get_domain_pass();
my $result = reset_AD_Password();
#Reset AD user password
sub reset_AD_Password {
my $ad = Net::LDAP->new($AD_passwords[0]);
my $msg = $ad->bind(dn => "cn=$AD_passwords[2],$AD_passwords[1]",
password => $AD_passwords[3],
version => 3);
if ($msg->code)
{
print "Error :" . $msg->error() . "\n";
exit 2;
}
my $acc_name = 'sAMAccountName';
my $acc_fullname = 'displayName';
my $acc_base = 'manager';
my $acc_distName = 'distinguishedName';
my $acc_mail = 'mail';
my $act = $ad->search(
base => "$AD_passwords[1]",
filter => "(&(objectCategory=person)(sAMAccountName=$sAN))",
attrs => [$acc_name, $acc_fullname, $acc_distName, $acc_mail]);
die 1 if ($act->count() !=1 );
my $samdn = $act->entry(0)->dn;
$fullname = $samdn->get_value($acc_fullname);
$mail = $samdn->get_value($acc_mail);
}
}
However we get an error on the line:
$fullname = $samdn->get_value($acc_fullname);
$mail = $samdn->get_value($acc_mail);
The error states "Can't locate object method "get_value" via package (distinguished Name) (perhaps you forgot to load (distinguished Name))"
However the code works correctly when we replace $samdn with the following code:
foreach my $entry ($act->entries){
$name = $entry->get_value($acc_name);
$fullname = $entry->get_value($acc_fullname);
$distName = $entry->get_value($acc_distName);
$mail = $entry->get_value($acc_mail);
}
It would appear that the code is unable to identify $samdn as a Net::LDAP::Entry record.
We have tried typecasting $samdn but got the same error.
Could someone help in resolving this issue as we would not prefer to use the for loop just in case more that one record is returned by the search? Thanks in advance.
You are not assigning a Net::LDAP::Entry to $samdn. You are assigning the dn of the first entry.
# VVVV
my $samdn = $act->entry(0)->dn;
Get rid of that ->dn and it should work, if $act->entry(0) returns a Net::LDAP::Entry.

How can I handle multiple outlook accounts using Perl

I have task to read mails from secondary mail account from outlook using perl.
Please check the following it may help you.But you should install respective modules.Reference from "http://www.perlmonks.org/?node_id=916759"
use Modern::Perl;
use Mail::POP3Client;
use MIME::QuotedPrint;
my $pop_user = 'XXXXXXXXXX';
my $pop_pass = 'XXXXXXXXXX';
my $pop_host = 'exchange3';
#connect to POP3 sever
my $pop = new Mail::POP3Client ( HOST => $pop_host );
$pop->User($pop_user);
$pop->Pass($pop_pass);
$pop->Connect()
or die "Unable to connect to POP3 server: ".$pop->Message()."\n";
#count number of items in POP3 mailbox
my $mailcount = $pop->Count();
for (my $i = 1; $i <= $mailcount ; $i++) {
my $header = $pop->Head($i); #gets the header
my $uni = $pop->Uidl($i); # gets the unquie id
my $body = $pop->Body($i);
$body = decode_qp($body); #decode quoted printable body
say "$uni";
say "$header\n";
say "$body";
}

Fetch all user information with Net::LDAP

Currently have an small perl script what for the given username fetch his email address from the ActiveDirectory using Net::LDAP.
The search part is the following:
my $user = "myuser";
my $mesg = $ldap->search(
base => "dc=some,dc=example,dc=com",
filter => '(&(sAMAccountName=' . $user . ')(mail=*))', #?!?
);
for my $entry ($mesg->entries) {
my $val = $entry->get_value('mail');
say "==$val==";
}
Working ok.
How i should modify the above statement to fetch all available information for the given user myuser? I'm looking to get an perl-ish data structure, such something like next:
my $alldata = search(... all info for the given $user ... );
say Dumper $alldata; #hashref with all stored informations for the $user
It is probably dead simple - but i'm an total AD & LDAP-dumb person...
Edit: When I dump out the $msg->entries (what is an LADP::Entry object) got something, but i'm not sure than it contains everything or only the part of the stored data...
I've done something similar, and I use this to query LDAP:
my $ldapResponse = $ldap->search(base => $base, filter => $filter, attrs => $attrs);
And then this to parse it:
if ($ldapResponse && $ldapResponse->count()) {
$ldapResponse->code && die $ldapResponse->error;
my %domainNames = %{$ldapResponse->as_struct};
foreach my $domainName (keys %domainNames) {
my %ldapResponse;
my %dnHash = %{$domainNames{$domainName}};
foreach my $attr (sort(keys %dnHash)) {
# Note that the value for each key of %dnHash is an array,
# so join it together into a string.
my $value = join(" ", #{$dnHash{$attr}});
$ldapResponse{$attr} = $value;
}
// Dump/use %ldapResponse
}
}
I've never tried to use the ldap->entries in your code, but the above works for me!
I explicitly specify a(long) list of attributes ($attr), but perhaps that's optional as your example shows, and you can get ALL LDAP fields by just skipping that arg to search().

Email::MIME can't parse message from Gmail

So I'm using PERL and Email::MIME to get an email from gmail. Here is my code:
use Net::IMAP::Simple::Gmail;
use Email::Mime;
# Creat the object that will read the emails
$server = 'imap.gmail.com';
$imap = Net::IMAP::Simple::Gmail->new($server);
# User and password
$user = 'username#gmail.com';
$password = 'passowrd';
$imap->login($user => $password);
# Select the INBOX and returns the number of messages
$numberOfMessages = $imap->select('INBOX');
# Now let's go through the messages from the top
for ($i = 1; $i <= $numberOfMessages; $i++)
{
$top = $imap->top($i);
print "top = $top\n";
$email = Email::MIME->new( join '', #{ $imap->top($i) } );
$body = $email->body_str;
print "Body = $body\n";
}#end for i
When I run it, I get the following error:
can't get body as a string for multipart/related; boundary="----=_Part_6796768_17893472.1369009276778"; type="text/html" at /Library/Perl/5.8.8/Email/Mime.pm line 341
Email::MIME::body_str('Email::MIME=HASH(0x87afb4)') called at readPhoneEmailFeed.pl line 37
If I replace
$body = $email->body_str;
with
$body = $email->body;
I get the output:
Body =
(i.e. empty string)
What's going on here? is there a way for me to get the raw body of the message (->body_raw doesn't work either)? I'm okay with parsing out the body using regex
Email::MIME is not the best documented package I have ever seen.
The body and body_str methods only work on a single mime part. Mostly that would be a simple text message. For anything more complex use the parts method to get each mime component which is itself an Email::MIME object. The body and body_str methods should work on that. An html formatted message will generally have two MIME parts: text/plain and text/html.
This isn't exactly what you want but should be enough to show you what is going on.
my #parts = $email->parts;
for my $part (#parts) {
print "type: ", $part->content_type, "\n";
print "body: ", $part->body, "\n";
}

Perl - How to get the email address from the FROM part of header?

I am trying to set up this script for my local bands newsletter.
Currently, someone sends an email with a request to be added, we manually add it to newsletter mailer I set up.
(Which works great thanks to help I found here!)
The intent now is to have my script below log into the email account I set up for the list on our server, grab the info to add the email automatically.
I know there are a bunch of apps that do this but, I want to learn myself.
I already have the "add to list" working when there is an email address returned from the header(from) below BUT, sometimes the header(from) is a name and not the email address (eg "persons name" is returned from persons name<email#address> but, not the <email#address>.)
Now, I am not set in stone on the below method but, it works famously... to a point.
I read all the docs on these modules and there was nothing I could find to get the darn email in there all the time.
Can someone help me here? Verbose examples are greatly appreciated since I am struggling learning Perl.
#!/usr/bin/perl -w
##########
use CGI;
use Net::IMAP::Simple;
use Email::Simple;
use IO::Socket::SSL; #optional i think if no ssl is needed
use strict;
use CGI::Carp qw(fatalsToBrowser warningsToBrowser);
######################################################
# fill in your details here
my $username = '#########';
my $password = '#############';
my $mailhost = '##############';
#######################################################
print CGI::header();
# Connect
my $imap = Net::IMAP::Simple->new($mailhost, port=> 143, use_ssl => 0, ) || die "Unable to connect to IMAP: $Net::IMAP::Simple::errstr\n";
# Log in
if ( !$imap->login( $username, $password ) ) {
print STDERR "Login failed: " . $imap->errstr . "\n";
exit(64);
}
# Look in the INBOX
my $nm = $imap->select('INBOX');
# How many messages are there?
my ($unseen, $recent, $num_messages) = $imap->status();
print "unseen: $unseen, <br />recent: $recent, <br />total: $num_messages<br />\n\n";
## Iterate through unseen messages
for ( my $i = 1 ; $i <= $nm ; $i++ ) {
if ( $imap->seen($i) ) {
my $es = Email::Simple->new( join '', #{ $imap->top($i) } );
printf( "[%03d] %s\n\t%s\n", $i, $es->header('From'), $es->header('Subject'));
print "<br />";
next;
}## in the long version these are pushed into different arrays for experimenting purposes
else {
my $es = Email::Simple->new( join '', #{ $imap->top($i) } );
printf( "[%03d] %s\n\t%s\n", $i, $es->header('From'), $es->header('Subject'));
print "<br />";
}
}
# Disconnect
$imap->quit;
exit;
use Email::Address;
my #addresses = Email::Address->parse('persons name <email#address>');
print $addresses[0]->address;
The parse method returns an array, so the above way works for me.
I'm making this a separate answer because even though this information is hidden in the comments of the accepted answer, it took me all day to figure that out.
First you need to get the From header using something like Email::Simple. THEN you need to extract the address portion with Email::Address.
use Email::Simple;
use Email::Address;
my $email = Email::Simple->new($input);
my $from = $email->header('From');
my #addrs = Email::Address->parse($from);
my $from_address = $addrs[0]->address; # finally, the naked From address.
Those 4 steps in that order.
The final step is made confusing by the fact that Email::Address uses some voodoo where if you print the parts that Email::Address->parse returns, they will look like simple strings, but they are actually objects. For example if you print the result of Email::Address->parse like so,
my #addrs = Email::Address->parse($from);
foreach my $addr (#addrs) { say $addr; }
You will get the complete address as output:
"Some Name" <address#example.com>
This was highly confusing when working on this. Granted, I caused the confusion by printing the results in the first place, but I do that out of habit when debugging.