I'm currently building a php scripts which fetches the email from a server using imap functions and stores the details in the database.
My problem is I dont know how to identify new mails from old mails that already exists.
and how to get reply mails sent to the mail
use the UID message to determine the last message, you have to store the last UID in the table
$uidsArray = imap_sort($imapConnection, SORTARRIVAL, 1, SE_UID);
if ($uidsArray) {
// read UID last message, XEmailUID - table(mailbox, lastuid mailbox)
$lastUIDObject = new XEmailUID();
$lastUIDObject->setImap($mailbox->getId().'/'.$mailboxRef);
if (!$lastUIDObject->select()) {
$lastUIDObject->insert();
}
$uidMax = 0;
foreach ($uidsArray as $uid) {
if ($uid < $lastUIDObject->getUid()) {
continue;
}
if ($uid >= $uidMax) {
$uidMax = $uid;
}
// your function
$this->_readIMAPMessage(
$imapConnection,
$uid,
$mailboxRef
);
}
if ($uidMax > 0) {
$lastUIDObject->setUid($uidMax);
$lastUIDObject->update();
}
}
Related
Im working with library:
https://github.com/ddeboer/imap
This is my part function:
$mailbox = $connection->getMailbox('INBOX');
// Loop through each email
foreach ($mailbox as $message)
{
// Check if the message already exists in the database
$this->db->where('message_number', $message->getNumber());
$query = $this->db->get('contacts');
// If the message doesn't exist in the database
if ($query->num_rows() == 0)
{
$subject = $message->getSubject();
// Determine the type of the message (new or reply)
if (preg_match('/^re:/i', $subject)) {
$message_type = "reply";
$this->helpdesk_model->insert_new_ticket($message, $message_type);
// Insert the attachments into the database
$attachments = $message->getAttachments();
$message_number = $message->getNumber();
foreach ($attachments as $attachment)
{
$this->helpdesk_model->insert_attachment_to_ticket($attachment, $message_number);
}
} else {
$this->load->model('email_model');
$message_type = "new";
$this->helpdesk_model->insert_new_ticket($message, $message_type);
$this->email_model->send_email_new_ticket_created($message);
// Insert the attachments into the database
$attachments = $message->getAttachments();
$message_number = $message->getNumber();
foreach ($attachments as $attachment)
{
$this->helpdesk_model->insert_attachment_to_ticket($attachment, $message_number);
}
}
}
}
Base on above function I read emails from INBOX and insert to Codeigniter3 database. Currently I add preg_match function, and in match re: in title then I insert this message as reply.
But how to add logic and get any parent ID original message + and each reply for this message?
I try get: message_number but every message have diffrent number, I also try get message_id but for all return for me 0 and im not sure how to get parent ID for all messages in one ticket.
I am using below code to read my gmail inbox and it's working fine for reading.
But the issue is some of the mail are not set as seen so they comes every time.
As per my observation mails which do not change there flag from unseen to seen are the mails which contains some HTML in it.
Below is my code:
public function getMessages($type = 'text') {
$stream = $this->imapStream;
$emails = imap_search($stream, 'UNSEEN');
$messages = array();
if ($emails) {
$this->emails = $emails;
$i = 0;
foreach ($emails as $email_number) {
$this->attachments = array();
$uid = imap_uid($stream, $email_number);
$messages[] = $this->loadMessage($uid, $type);
if ($i == $this->limit) {
break;
}
$i++;
echo "seen status=>".imap_setflag_full($stream, $email_number, "\\Seen", ST_UID);
//echo "seen status=>".imap_clearflag_full($stream, $email_number, "\\Seen");
}
}
return $messages;
}
This is the line i am using to manually change status
echo "seen status=>".imap_setflag_full($stream, $email_number, "\\Seen", ST_UID);
seen status always return 1 as result but in inbox it shows as unread.
You are using Message Sequence Numbers (MSNs), but providing the ST_UID flag to your flag functions, changing them to use UIDs. Most MSNs will not generally be valid UIDs.
Either use UIDs everywhere (with FT_UID and ST_UID and the like to all functions) or MSNs everywhere (never use UID flags, and don't expunge anything while looping.)
imap_setflag_full($stream, $email_number, "\\Seen");
or
imap_setflag_full($stream, $uid, "\\Seen", ST_UID);
If you use the UID version of search, you don't need to call imap_uid.
I am trying to fetch email using imap function which return very old email. Following script i am trying
$imap = #imap_open("{mail.******.com:143/novalidate-cert}", $sEmail, $sPwd);
$message_count = #imap_num_msg($imap);
for ($m = 1; $m <= $message_count; ++$m){
$header = #imap_rfc822_parse_headers(imap_fetchheader($imap, $m));
$email[$m]['from'] = $header->from[0]->mailbox.'#'.$header->from[0]->host;
}
Currently above function return email in ascending order, so that's why very old emails (2015's Email) are coming first. So is there any way to get recent email first.
I want to make a mail send program and notify the user with a progress bar while waiting. Unfortunately it does not work as expected, the progressbar is not updated.
The Program loops through an array of mail adresses derived from a database. There first the mail address will be verified fro existence in the mailbox. If not, it will be reported. The reports are collected and at the end sent back to the browser.
The progress is reported by separate ajax posts every second by the javascript function "mitgl.progressBar" and sent by the server via the function "getProgress" at the bottom of the php.
Mail verification and mail sending works but the getProgress seems only be made once instead.
Altough the attached code is only a fragment, the rest of the code works fine.
I cannot find the problem, perhaps someone can see what i am blind for...
Javascript:
versandMail: function() {
mitgl.unselectRec();
mitgl.pInt = window.setInterval(mitgl.progressBar, 1000);
var oForm = $('form[name=vs]').get(0);
$.post(location.href, {
cmd: 'M mailVersand',
de: oForm.de.value,
fr: oForm.fr.value,
sr: oForm.sr.value,
aktiv: oForm.aktiv.value,
anfragen: oForm.anfragen.value,
vorstand: oForm.vorstand.value,
idList: (oForm.idList ? oForm.idList.value : ''),
betreff: oForm.betreff.value,
mailtext: $('textarea[name=mailtext]', oForm).htmlarea('html'),
attachments: JSON.stringify(mitgl.oVersand.mail.attachments)
}, function(data, status, oXhr){
window.clearInterval(mitgl.pInt);
$('#progressbar').remove();
$('#mailReport').remove();
if (data.isEmpty()) {
window.alert('Auswahl hat keine Adressen ergeben');
} else if (data.substr(0, 6) === 'Fehler') {
window.alert(data);
} else {
$('#protokoll tbody').html(data);
mitgl.protoLink();
mitgl.selectTop();
}
});
},
progressBar: function() {
$.post(location.href, {
cmd: 'M getProgress'
}, function(nProgress) {
if ($('#progressbar').length > 0) {
$('#progressbar .bar').css({width: nProgress+'%'});
} else {
var pb = $('<div/>')
.attr('id', 'progressbar')
.appendTo('#cmd');
$('<div/>')
.addClass('bar')
.appendTo(pb);
}
});
},
PHP:
function mailVersand() {
// ... Prepare Mail Data ...
require_once 'phpmailer.class.php';
require_once('class.smtp.php');
require_once('class.verifyEmail.php');
$oVerify = new verifyEmail();
$oVerify->setEmailFrom($cMailFrom);
$oMail = new PHPMailer();
$oMail->SMTPDebug = 0;
$oMail->IsSMTP(); // telling the class to use SMTP
//
// ... and so on ...
$oMail->Host = ...
$aErrors = [];
$nSent = 0;
$nError = 0;
$nProcessed = 0;
$nMails = count($aMitglied);
session_start(); // <-- Session starts
$_SESSION['nProgress'] = '0'; // progress is zero
// loop through mailing list
foreach ($aMitglied as $r) {
$aEmail = explode(';', $r->email);
$email = $aEmail[0];
if ($oVerify->check($email)) {
$oMail->AddAddress($email,"$r->vorname $r->name");
// mail verificatio is ok, try to send
if ($oMail->send() === TRUE) {
$nSent++;
} else {
// no, report error
$e = new stdClass();
$e->email = $email;
$e->name = $r->name;
$e->vorname = $r->vorname;
$e->error = $oMail->ErrorInfo;
$aErrors[] = $e;
$nError++;
}*/
$oMail->ClearAddresses();
} else {
// Mail verification failed, report error
$e = new stdClass();
$e->email = $r->email;
$e->name = $r->name;
$e->vorname = $r->vorname;
$e->error = $oVerify->getAllErrors();
$aErrors[] = $e;
$nError++;
}
$nProcessed++; // <-- Next processed record
// v-- Calulate percentage of progress
$_SESSION['nProgress'] = strval(round($nProcessed *100 /$nMails));
}
// create error report
$oBericht = new stdClass();
$oBericht->sent = $nSent;
$oBericht->error = $nError;
$oBericht->fails = $aErrors;
// now procedure finished, reply final report
// ....
$s = $this->listVersand();
echo ($s); // send reply
session_write_close(); // session ends
exit;
}
function getProgress() {
session_start();
//$n = isset($_SESSION['nProgress']) ? "$_SESSION[nProgress]" : "5";
$n="20";
echo ($n);
exit();
}
I found the problem. Sessions can store values between successive calls to a webpage. What I was intended to do is passing a value between active PHP processes.
One way to do this is using APC calls. However this is not available anymore in php versions newer than 5.3, so I have chosen a way to store the progress information in a database.
It's not very effective, it uses a lot of recources. If someone knows a better way to share variables between active php processes it would be nice to tell it here.
I'm trying to build a small webmail app. When I read all the emails in inbox I want to show for each mail if it has attachments. This works, but the problem is that it takes to long to do that, about 0.5 secs for 1Mb email attach. Multiply that with all emails in inbox that have big attach files :|
My question is: How to check if an email has attach withouth loading the whole email ? Is that possible ?
Bellow is the code I'm using now:
function existAttachment($part)
{
if (isset($part->parts))
{
foreach ($part->parts as $partOfPart)
{
$this->existAttachment($partOfPart);
}
}
else
{
if (isset($part->disposition))
{
if ($part->disposition == 'attachment')
{
echo '<p>' . $part->dparameters[0]->value . '</p>';
// here you can create a link to the file whose name is $part->dparameters[0]->value to download it
return true;
}
}
}
return false;
}
function hasAttachments($msgno)
{
$struct = imap_fetchstructure($this->_connection,$msgno,FT_UID);
$existAttachments = $this->existAttachment($struct);
return $existAttachments;
}
To check whether the email has attachment, use $structure->parts[0]->parts.
$inbox = imap_open($mailserver,$username, $password, null, 1, ['DISABLE_AUTHENTICATOR' => 'PLAIN']) or die(var_dump(imap_errors()));
$unreadEmails = imap_search($inbox, 'UNSEEN');
$email_number = $unreadEmails[0];
$structure = imap_fetchstructure($inbox, $email_number);
if(isset($structure->parts[0]->parts))
{
// has attachment
}else{
// no attachment
}
imap_fetchstructure does fetch the whole email content in order to analyze it. Sadly there is no other way to check for attachment.
Maybe you can use the message size info from imap_headerinfo to get a prediction if the message will have attachments.
Another way is to fetch the emails in an regular interval in the background and store them with their content and UID for later lookup in a database. You need to do that later anyway when you want so search for specific messages. (You do not want to scan the while imap account when searching for "dinner")