I take data from Gmail with this code
<?php $data = array(
// email account
'email' => array(
'hostname' => '{imap.gmail.com:993/imap/ssl}INBOX',
'username' => $emailAddress,
'password' => $emailPassword
),
// inbox pagination
'pagination' => array(
'sort' => $sortBy,
'limit' => 10,
'offset' => $offset
)
);
$result = array();
$imap = imap_open($data['email']['hostname'], $data['email']['username'], $data['email']['password']) or die ('Cannot connect to yourdomain.com: ' . imap_last_error());
$read = imap_search($imap, 'ALL');
$overview = imap_fetch_overview($imap, $read[$i], 0);
$header = imap_headerinfo($imap, $read[$i], 0);
$mail = $header->from[0]->mailbox . '#' . $header->from[0]->host;
$image = '';
$structure = imap_fetchstructure($imap, $read[$i]);
if(isset($structure->parts) && is_array($structure->parts) && isset($structure->parts[1])) {
$part = $structure->parts[1];
if($part->encoding == 3) {
$message = imap_fetchbody($imap,$read[$i],1.2);
$message = imap_qprint($message);
} else if($part->encoding == 1) {
$message = imap_8bit($message);
} else {
$message = imap_fetchbody($imap,$read[$i],2);
$message = imap_qprint($message);
}
}else{
$message = imap_body($imap, $read[$i],0);
}
?>
All data I receive correctly, however when I enter Email list page, the received emails turn to read.
It worked fine before, after using for some time, this issue appeared.
Any idea what can be the reason?
In imap_fetchbody, add the FT_PEEK flag to prevent clearing the \Seen flag automatically.
imap_fetchbody($imap, $read[$i], 1.2, FT_PEEK);
See option flag documentation at the official site.
Related
can someone help me a bit with PhpMailer form? I'm not a php dev and i'm a bit lost, mostly because I have no idea how to debug it.
Tips how to debug such scripts are very welcome! (I don't know how to do it in localhost and I host it in a web shared host so I cannot ssh the server)
This is the script:
I have a multiple step form from Frontend which has also recaptcha, so the script include validation of different form steps and recaptcha validation.
<?php
require_once("/PHPMailer/PHPMailer.php");
use PHPMailer\PHPMailer\PHPMailer;
$t_mailer = new PHPMailer;
$t_mailer->SMTPAuth = true;
$t_mailer->Username = "myemail#gmail.com"; // gmail username
$t_mailer->Password = "****"; //gmail password
$t_mailer->SMTPSecure = 'tls';
$t_mailer->Port = 587;
$t_mailer->setFrom("myemail#gmail.com", "Name for the owner of the Account");
//$t_mailer->addAddress("myemail#gmail.com", "Name for who is being sent the email.");
$t_mailer->Subject = "Project request from ECA";
$t_mailer->Body = "This will be the message body that is sent.";
// $recipient = 'myemail#gmail.com'; // Enter the recipient's email address here.
// $subject = 'Project request from ECA'; // Enter the subject of the email here.
$success = 'Your message was sent successful. Thanks.';
$error = 'Sorry. We were unable to send your message.';
$invalid = 'Validation errors occurred. Please confirm the fields and submit it again.';
if ( ! empty( $_POST ) ) {
require_once('recaptcha.php');
if( isset( $_POST['email'] ) ) {
$from = filter_var( $_POST['email'], FILTER_VALIDATE_EMAIL );
} else {
$from = null;
}
if( isset( $_POST['step'] ) ) {
$step = $_POST['step'];
} else {
$step = 'send';
}
if ( ! empty( $_POST['reCAPTCHA'] ) ) {
if ( ! empty( $reCAPTCHA['success'] ) ) {
$errCaptcha = '';
} else {
$errCaptcha = true;
}
} else {
$errCaptcha = '';
}
$errFields = array();
foreach( $_POST as $key => $value ) {
if ( $key != 'section' && $key != 'reCAPTCHA' ) {
if ( $key == 'email' ) {
$validation = filter_var( $_POST[$key], FILTER_VALIDATE_EMAIL );
} else {
$validation = ! empty( $_POST[$key] );
}
if ( ! $validation ) {
$errFields[$key] = true;
}
}
}
if ( empty( $errCaptcha ) && count( $errFields ) === 0 && $step === 'send' ) {
$header = "From: " . $from . " <" . $from . ">" . "\r\n";
$header .= "MIME-Version: 1.0\r\n";
$header .= "Content-type: text/html\r\n";
$body = '<table style="padding: 35px; background-color: #f5f5f5"; font-family: Roboto, sans-serif; font-size: 1rem; text-align: left; border-radius: 4px>';
$body .= '<tr><th style="font-size: 1.5rem; font-weight: 600; color: #1E50BC">'.$subject.'</th></tr>';
$body .= '<tr></td>';
foreach( $_POST as $key => $value ) {
if ( $key != 'section' && $key != 'reCAPTCHA' ) {
$body .= '<p><b>' . str_replace( '-', ' ', ucfirst( $key ) ) . '</b>: ' . $value . '</p>';
}
}
$body .= '</td></tr>';
$body .= '</table>';
$t_mailer->Body = $body;
$t_mailer->addAddress($from, 'who send the email');
// $mail = mail( $recipient, $subject, $body, $header );
// $mail
if ( $t_mailer->send() ) {
$response = array(
'status' => 'success',
'info' => $success
);
print_r( json_encode( $response ) );
} else {
$response = array(
'status' => 'fail',
'info' => $error
);
print_r( json_encode( $response ) );
}
} else {
$response = array(
'status' => 'invalid',
'info' => $invalid,
'captcha' => $errCaptcha,
'fields' => $errFields,
'errors' => count( $errFields )
);
print_r( json_encode( $response ) );
}
exit;
}
I'm sure PhpMailer works with my host and my server because I tried a very simple script that send an email from root and it worked. (I got the email in my gmail inbox)
But This script is in another folder, not root, even tho they all have same folder/files permission (not sure if is relevant, but better specify!)
Several things not quite right here.
When you're using PHPMailer without composer, you need to load all the classes it needs yourself, so add:
require_once '/PHPMailer/SMTP.php';
require_once '/PHPMailer/Exception.php';
You are setting some SMTP config properties, but not actually telling PHPMailer to use SMTP, so add this:
$t_mailer->isSMTP();
You're sending from a gmail address, which means you must send through gmail's servers (or you will fail SPF checks), but you have not specified a server to send through, so set this:
$t_mailer->Host = 'smtp.gmail.com';
Your content is in HTML, but you're not asking PHPMailer to send it as HTML:
$t_mailer->isHTML();
You don't need any of that stuff you're doing with $header; PHPMailer does all that for you.
Rather than going any further, I'd recommend basing your code on the gmail example provided with PHPMailer, and if you run into any other issues, refer to the PHPMailer troubleshooting guide and search on here.
I am experiencing some strange behavior when using json_encode.
This is my code:
if($_POST["action"] == 'profile')
{
sleep(2);
$error = '';
$success = '';
$admin_name = '';
$admin_contact_no = '';
$admin_email = '';
$admin_profile = '';
$data = array(
':admin_email' => $_POST["admin_email"],
':admin_id' => $_POST['hidden_id']
);
$visitor->query = "
SELECT * FROM admin_table
WHERE admin_email = :admin_email
AND admin_id != :admin_id
";
$visitor->execute($data);
if($visitor->row_count() > 0)
{
$error = '<div class="alert alert-danger">User Email Already Exists</div>';
}
else
{
$user_image = $_POST["hidden_user_image"];
if($_FILES["user_image"]["name"] != '')
{
$user_image = upload_image();
}
$admin_name = $visitor->clean_input($_POST["admin_name"]);
$admin_contact_no = $_POST["admin_contact_no"];
$admin_email = $_POST["admin_email"];
$admin_profile = $user_image;
$data = array(
':admin_name' => $admin_name,
':admin_contact_no' => $admin_contact_no,
':admin_email' => $admin_email,
':admin_profile' => $admin_profile
);
$visitor->query = "
UPDATE admin_table
SET admin_name = :admin_name,
admin_contact_no = :admin_contact_no,
admin_email = :admin_email,
admin_profile = :admin_profile
WHERE admin_id = '".$_POST['hidden_id']."'
";
$visitor->execute($data);
$success = '<div class="alert alert-success">User Details Updated</div>';
}
$output = array(
'error' => $error,
'success' => $success,
'admin_name' => $admin_name,
'admin_contact_no' => $admin_contact_no,
'admin_email' => $admin_email,
'admin_profile' => $admin_profile
);
echo json_encode($output);
}
Alert message for $error displays accordingly while alert message for $success does not.
If I swap positions between $error = '<div class="alert alert-danger">User Email Already Exists</div>'; and $success = '<div class="alert alert-success">User Details Updated</div>';, $error still works while $success still does not, which deeply confuses me.
I know I can avoid all this trouble by using echo, but I really want to find out what the issue is here.
Thank you for your help.
It was just a spelling error, wrote "succes" instead of "success".
I apologize for the trouble and thank you for your help.
I am trying to fetch the all email received from a particular email id eg (From: abc#gmail.com),which i am successfully getting.
Now i am looking forward to get all the messages which are in thread to this email ie Re:sub fw:, Re:Re....
Here is how i am trying
$username = 'myemail#gmail.com';
$password = 'mypassword';
$folder = 'INBOX';
$email_resp = $this->config_imap($username,$password,$folder);
$email_list = $email_resp['emails'];
$inbox = $email_resp['inbox'];
$student_email = $useremail;
$email_list = imap_search($inbox, "FROM '{$student_email}'");
$threads = imap_thread($inbox);
rsort($email_list);
if(sizeof($email_list)>0){
foreach ($email_list as $key => $value) {
$overview = imap_fetch_overview($inbox,$value,0);
$message = imap_fetchbody($inbox,$value,2);
$attachment = imap_fetchstructure($inbox,$value);
$threads = imap_thread($inbox);
$thread_detail = array(
$value.".num" => $threads[$value.".num"],
$value.".next" => $threads[$value.".next"],
$value.".branch" => $threads[$value.".branch"],
);
foreach ($thread_detail as $k => $v) {
$tree =explode('.',$k);
if($tree[1]=='num'){
$headerInfo=imap_headerinfo($inbox, $value);
}
}
echo json_encode($headerInfo);
die;
$overview[0]->email =$message;
$overview[0]->attachment =$attachment;
$emails[]=$overview;
}
echo json_encode($emails);
}
else{
return Response::json(array('fail'=>'No Email Found.'));
}
How may i get the associated threads header details and message body too.
Re-visiting this problem specified in my previous question, I tried and tried, also with different accounts (I tried gmail, as well as outlook), but the problem still persists. The error I get is the following if I try to access my google account
Error: Unable to get imap_thread after 4 retries. 'Can't open mailbox {imap.gmail.com:993/ssl/imap/tls/novalidate-cert}INBOX: invalid remote specification'
if I try accessing email on my outlook account, the error is the same :
Error: Unable to get imap_thread after 4 retries. 'Can't open mailbox {outlook.office365.com:993/ssl/imap/tls/novalidate-cert}INBOX: invalid remote specification'
My setup is as follows :
public $emailTicket = array(
'datasource' => 'ImapSource',
'server' => 'outlook.office365.com',
'connect' => 'imap/tls/novalidate-cert',
'username' => 'my email here',
'password' => 'my password here',
'port' => '993', //incoming port
'ssl' => true,
'encoding' => 'UTF-8',
'error_handler' => 'php',
'auto_mark_as' => array(
'Seen',
// 'Answered',
// 'Flagged',
// 'Deleted',
// 'Draft',
),
);
I am working on a local machine, does anyone know if this might be the problem or not? Has anyone ever tried this and worked for him/her? I am open to all input!
I can't seem to find what's wrong here, I've been at this for about 2days now, so if anyone can help, I appreciate it!
Also here's the link for the plugin i'm using, by Nicolas Ramy..
You can use the following implemented code to fulfill your requirements:
public function generate_email_response_pdf()
{
$this->layout = false;
$this->autoRender = false;
$username = EMP_SMTP_MAIL_FROM;
$password = EMP_SMTP_MAIL_PASSWORD;
$imap = imap_open('{imap.gmail.com:993/imap/ssl/novalidate-cert}INBOX', $username, $password);
$emails = imap_search($imap, 'ALL');
if(!empty($emails))
{
//put the newest emails on top
rsort($emails);
foreach($emails as $email_number)
{
$flag = 0;
$mail_data = array();
$file_name = array();
$output = array();
$savefilename = null;
$filename = null;
$overview = imap_fetch_overview($imap, $email_number, 0);
//initialize the subject index with -000, considering not receving this will not be received in
//subject line of email
$output['subject'] = '-000x';
if(isset($overview[0] -> subject))
{
$output['subject'] = $overview[0] -> subject;
}
$structure = imap_fetchstructure($imap, $email_number);
if(property_exists($structure, 'parts'))
{
$flag = 1;
$flattened_parts = $this->flatten_parts($structure->parts);
foreach($flattened_parts as $part_number => $part)
{
switch($part->type)
{
case 0:
//the HTML or plain text part of the email
if((isset($part->subtype)=='HTML')&&(isset($part->disposition)=='ATTACHMENT'))
{
$part_number = 1.2;
}
else if(isset($part->subtype)=='HTML')
{
$part_number = $part_number;
}
else
{
$part_number = $part_number;
}
$message = $this->get_part($imap, $email_number, $part_number, $part->encoding);
//now do something with the message, e.g. render it
break;
case 1:
// multi-part headers, can ignore
break;
case 2:
// attached message headers, can ignore
break;
case 3: // application
case 4: // audio
case 5: // image
case 6: // video
case 7: // other
break;
}
if(isset($part->disposition))
{
$filename = $this->get_filename_from_part($part);
if($filename)
{
// it's an attachment
$attachment = $this->get_part($imap, $email_number, $part_number, $part->encoding);
$file_info = pathinfo($filename);
$savefilename = RESPONSE_ATTACHMENT_PREFIX.$file_info['filename'].'_'.$this->_getRandId(4).'.'.$file_info['extension'];
$file_name[] = $savefilename;
$attachment_file_name = $this->save_attachment($attachment, $savefilename, $directory_path);
//imap_fetchbody($imap, $email_number, 2); //This marks message as read
}
else
{
// don't know what it is
}
}
}
}
else
{
$encoding = $structure->encoding;
$message = imap_fetchbody($imap, $email_number, 1.2);
//echo $message; die;
if($message == "")
{
$message = imap_body($imap, $email_number);
if($encoding == 3)
{
$message = base64_decode($message);
}
else if($encoding == 4)
{
$message = quoted_printable_decode($message);
}
}
}
$header = imap_headerinfo($imap, $email_number);
$from_email = $header->from[0]->mailbox."#".$header->from[0]->host;
$to_email = $header->to[0]->mailbox."#".$header->to[0]->host;
$reply_to_email = $header->reply_to[0]->mailbox."#".$header->reply_to[0]->host;
$cc_email = array();
if(isset($header->cc))
{
foreach($header->cc as $ccmail)
{
$cc_email[] = $ccmail->mailbox.'#'.$ccmail->host;
}
$cc_email = implode(", ", $cc_email);
}
$output['to'] = $to_email;
$output['from'] = $from_email;
$output['reply_to'] = $reply_to_email;
$output['cc'] = $cc_email;
$formatted_date = date('D, d M Y h:i A', strtotime($overview[0] -> date));
$output['date'] = $formatted_date;
$output['message'] = $message;
$output['flag'] = $flag;
$mail_data['Attachment'] = $file_name;
$mail_data['Data'] = $output;
$this->set('response_data', $mail_data);
$mail_content = null;
if(!empty($mail_data))
{
$this->viewPath = 'Elements/default';
$mail_content = $this->render('pdf_content');
}
$header = null;
$footer = null;
$html = preg_replace(array('/[^\r\n\t\x20-\x7E\xA0-\xFF]*/'), '', $mail_content);
$pdfFile = $this->_generateWkPdf($html, $directory_path, $new_file_name, $header, $footer);
$image_type = EXT_JPG;
$response_files_array = $this->_generateImagesFromPdf($directory_path.$pdfFile, $directory_path, $new_file_name, $image_type);
}
}
imap_close($imap);
}
I have written/copied a script that reads emails from an inbox and updates a ticket and then moves the email to a proccessed folder. This all works perfectly on new emails to the inbox but when someone replys to an email and it ends up in the inbox my scrtipt reads nothing on the email.
Is there something different to the way an email is structured when its a reply? I need a way of reading whats in the email so I can update a ticket with the contents. Knowing which email it is to update is all taken care of its just purely reading the content Im struggling with.
Here is the code
class Email
{
// imap server connection
public $conn;
// inbox storage and inbox message count
public $inbox;
private $msg_cnt;
// email login credentials
private $server = '????????????';
private $user = '????????';
private $pass = '?????????????';
private $port = ??;
// connect to the server and get the inbox emails
function __construct()
{
$this->connect();
$this->inbox();
}
function getdecodevalue($message,$coding)
{
switch($coding) {
case 0:
case 1:
$message = imap_8bit($message);
break;
case 2:
$message = imap_binary($message);
break;
case 3:
case 5:
$message=imap_base64($message);
break;
case 4:
$message = imap_qprint($message);
break;
}
return $message;
}
// close the server connection
function close()
{
$this->inbox = array();
$this->msg_cnt = 0;
imap_close($this->conn);
}
// open the server connection
// the imap_open function parameters will need to be changed for the particular server
// these are laid out to connect to a Dreamhost IMAP server
function connect()
{
$this->conn = imap_open("{".$this->server.":".$this->port."/imap/novalidate-cert}INBOX", $this->user, $this->pass);
}
// move the message to a new folder
function move($msg_index, $folder='Read')
{
// move on server
imap_mail_move($this->conn, $msg_index, $folder);
// re-read the inbox
//$this->inbox();
}
// get a specific message (1 = first email, 2 = second email, etc.)
function get($msg_index=NULL)
{
if(count($this->inbox) <= 0)
{
return array();
}
elseif( ! is_null($msg_index) && isset($this->inbox[$msg_index]))
{
return $this->inbox[$msg_index];
}
return $this->inbox[0];
}
// read the inbox
function inbox()
{
$this->msg_cnt = imap_num_msg($this->conn);
$in = array();
for($i = 1; $i <= $this->msg_cnt; $i++)
{
$in[] = array(
'index' => $i,
'header' => imap_headerinfo($this->conn, $i),
'body' => $this->cleanBody(imap_fetchbody($this->conn, $i,1)),
'structure' => imap_fetchstructure($this->conn, $i)
);
}
$this->inbox = $in;
}
function cleanBody($body)
{
$delimiter = '#';
$startTag = '----------START REPLY----------';
$endTag = '----------END REPLY----------';
$regex = $delimiter . preg_quote($startTag, $delimiter)
. '(.*?)'
. preg_quote($endTag, $delimiter)
. $delimiter
. 's';
preg_match($regex,$body,$matches);
$ret = trim($matches[1]);
return $ret;
}
}
$emails = new Email();
$email = array();
$emailCount = 1;
foreach($emails->inbox as $ems => $em)
{
$email[$emailCount]['subject'] = $sub = $em['header']->subject;
//echo $sub;
$subParts = explode('-',$sub);
$ticketUniqueCode = trim($subParts[1]);
$sql = "SELECT * FROM ticket_main WHERE uniquecode = '".mysql_escape_string($ticketUniqueCode)."' LIMIT 1";
$query = mysql_query($sql);
if(mysql_num_rows($query))
{
$res = mysql_fetch_object($query);
$ticketBody = $em['body'];
$customerID = $res->customerID;
$sql2 = "INSERT INTO ticket_updates SET ticketID = '".$res->ticketID."' , submitted = NOW() , submittedBy = '".$res->customerID."' , message = '".mysql_escape_string($ticketBody)."' , inhouse = 0";
$query = mysql_query($sql2);
// attachment section
$message_number = $em['index'];
$attachments = array();
if(isset($em['structure']->parts) && count($em['structure']->parts))
{
//echo 'hi';
for($i = 0; $i < count($em['structure']->parts); $i++)
{
$attachments[$i] = array(
'is_attachment' => false,
'filename' => '',
'name' => '',
'attachment' => ''
);
if($em['structure']->parts[$i]->ifdparameters) {
foreach($em['structure']->parts[$i]->dparameters as $object)
{
if(strtolower($object->attribute) == 'filename')
{
$attachments[$i]['is_attachment'] = true;
$attachments[$i]['filename'] = $object->value;
}
}
}
if($em['structure']->parts[$i]->ifparameters) {
foreach($em['structure']->parts[$i]->parameters as $object)
{
if(strtolower($object->attribute) == 'name')
{
$attachments[$i]['is_attachment'] = true;
$attachments[$i]['name'] = $object->value;
}
}
}
if($attachments[$i]['is_attachment'])
{
$attachments[$i]['attachment'] = imap_fetchbody($emails->conn, $message_number, $i+1);
if($em['structure']->parts[$i]->encoding == 3)
{ // 3 = BASE64
$attachments[$i]['attachment'] = base64_decode($attachments[$i]['attachment']);
}
elseif($em['structure']->parts[$i]->encoding == 4)
{ // 4 = QUOTED-PRINTABLE
$attachments[$i]['attachment'] = quoted_printable_decode($attachments[$i]['attachment']);
}
}
if(isset($em['structure']->parts[$i]->disposition) && $em['structure']->parts[$i]->disposition == "attachment")
{
$filename = $attachments[$i]['name'];
$mege="";
$data="";
$mege = imap_fetchbody($emails->conn, $message_number, $i+1);
$filename= $filename;
$fp=fopen('???????????????'.$filename,"w");
$data=$emails->getdecodevalue($mege,$em['structure']->parts[$i]->type);
fputs($fp,$data);
fclose($fp);
$email[$emailCount]['attachment'] = $attachments;
}
}
}
}
$emailCount++;
}
$emailNumbers = imap_search($emails->conn,'ALL');
if(!empty($emailNumbers))
{
foreach($emailNumbers as $a)
{
$emails->move($a);
}
imap_expunge($emails->conn);
}
$emails->close();
Hope that makes some sense and someone can actually help.
Many many thanks in advance
Jon
Well the most obvious thing is your code assumes a message is always in part 1, your line:
'body' => $this->cleanBody(imap_fetchbody($this->conn, $i,1)),
Means it's only looking at body 1. If it's a pure text email body 1 will be right, but if it's multipart/alternative (text & html) body 1 would be the base MIME message which tells you that there are sub bodies (body 1.1, 1.2) that actually contain the content.
Further if the reply includes embedded images, or includes the message it's replying to as an attachment then you could have even more bodies/locations.
So how do I find the body? (you ask)... well you can use imap_fetchstructure to learn about all the body parts, then search through it to find a piece with type=0 (text) and then download that body part. (The first found text should be the right one, but note there could be more than one text body type in an email).