PHP Imap get message body - php

I am connection to a mailbox and getting header information for each message like this:
$mailbox = new PhpImap\Mailbox(
env('MAIL_IMAP_PATH') . env('MAIL_FOLDER'), // IMAP server and mailbox folder
env('MAIL_LOGIN'), // Username for the before configured mailbox
env('MAIL_PASSWORD') // Password for the before configured username
);
$mailsIds = $mailbox->searchMailbox('ALL');
foreach($mailsIds as $mail_elem) {
$mail = $mailbox->getMail($mail_elem);
}
getMail gives me all the header infos without the body. I have checked now every single method which exists on $mailbox-> and there is no way to get the body. What am I doing wrong here?
Second approach is to use the stream from imap_open() and imap_fetchbody(). This feels more like a workarround because I connect a second time to the mailbox, but is also does not work:
foreach($mailsIds as $mail_elem) {
$imap_stream = imap_open(env('MAIL_IMAP_PATH') . env('MAIL_FOLDER'),
env('MAIL_LOGIN'), env('MAIL_PASSWORD'));
$message = imap_fetchbody($imap_stream, $mail_elem, 1.1);
}
I am getting an error:
imap_fetchbody(): Bad message number
Someone has an idea what is going on?

You have to get the body with the $mail object not the $mailbox object.
foreach($mailsIds as $mail_elem) {
$mail = $mailbox->getMail($mail_elem);
$message = $mail->textHtml;
}

This isn't the cause but the third parameter of fetchbody is a string, not a float, so write it like:
imap_fetchbody($imap_stream, $mail_elem, '1.1')
Your issue is probably about $mail_elem that's probably doesn't match with the index of the imap. In case they are UID, you need to add the flag FT_UID in the 4th paramates of imap_fetchbody.
Anyaway if you are planning to use imap_* library, I advise you to use this wrapper: php-taniguchi (it's quite documented and it has an example file).
The read() method is quite simple:
read(int $from, int $number, bool $details = false, bool $seen = false, bool $attachments = false)
Set all to true and you will get everything you want, it's quite easy:
$tmp = new \Taniguchi\Imap($account, $password, $url, $port);
$tmp->setSsl()->setValidate(false);
var_dump($tmp->read(1, 2, true, true, true));

Related

PHP imap_fetchbody returns always false after reading empty mailbox/folder although mail is existing

I am familiar with PHP but quite new to IMAP processing. I try to read a mailbox for getting the body processed. This is working fine until the mailbox runs empty. After the first access to the empty INBOX (or even any folder or subfolder of the mailbox, I tried several settings), the imap_fetchbody() always returns false althought the box contains new mails again.
This is my code:
$imap = '{imap.strato.de:993/imap/ssl/novalidate-cert}INBOX';
$user = 'myuser';
$pass = 'mypassword';
$imapStream = imap_open($imap, $user, $pass);
$mailIds = imap_search($imapStream, 'ALL', SE_UID, 'ISO-8859-1');
foreach ($mailIds as $mailId) {
$info = imap_mailboxmsginfo ( $imapStream );
$body = imap_fetchbody ( $imapStream, $mailId, '1');
if($body) {
... do something with the body ...
}
imap_delete($imapStream, $mailId, FT_UID);
}
imap_close($imapStream, CL_EXPUNGE);
Could solve the Problem as follows:
This line gets all Mail-Ids from the Mailbox, cause of the flag=SE_UID):
$mailIds = imap_search($imapStream, 'ALL', SE_UID, 'ISO-8859-1');
But imap_fetchbody() wants to have a Mail-Number as default. Mail-Id and Mail-Number differ in most cases, so that imap_fetchbody() failed with the given Mail-Id, beacause this was a different int value as the expected Mail-Number.
Adding the Flag FT_UID in the following line solved the Problem:
imap_fetchbody($imapStream, $mailId, '1', FT_UID);
A typical IMAP newbie mistake? Never mind, I'm happy now :)

Can I use IMAP to create a message in Exchange which can be opened, edited and send with a mail client?

I spend the best part of today trying to create a message with PHP via IMAP in Exchange which I can open in my mail client, edit and send.
I can create a message in the Draft folder (or any other folder), I can set the FLAGGED flag using the UID, but I cannot set the message to Draft. I create the message with imap_append and set the flags with imap_setflag_full.
Either the setting of the \Draft flag is ignored or the \Draft flag is not the same as creating a message with the mail client and not sending it.
Is the first the case and am I overlooking something? Or is the later the case and am I expecting something IMAP / Exchange does not support?
Who has the experience to answer this?
As requested by cnd (base code without checks and validations):
// Create connection with the mail box
$this->o_mailbox = imap_open($o_company->draftbox, $o_company->username, $o_company->password);
// Create header
$a_header["from"] = $o_company->name.' <'.$o_company->address.'>';
$a_header["to"] = $s_to_name.' <'.$s_to_email.'>';
if(isset($s_cc)) $a_header["cc"] = $s_cc;
$a_header["subject"] = $s_subject;
// Add multipart to body
$a_body[0]["type"] = TYPEMULTIPART;
$a_body[0]["subtype"] = "mixed";
// Add content to body
$a_body[1]["type"] = TYPETEXT;
$a_body[1]["subtype"] = "html";
$a_body[1]["charset"] = "utf-8";
$a_body[1]["disposition.type"] = "inline";
$a_body[1]["description"] = "";
$a_body[1]["contents.data"] = str_replace('[BODY]', $s_message, $o_company->template);
// Loop trough the attachment
foreach ($a_attachments as $a_attachment) {
$a_part["type"] = TYPEAPPLICATION;
$a_part["encoding"] = ENCBINARY;
$a_part["subtype"] = "pdf";
$a_part["disposition.type"] = "attachment";
$a_part["description"] = $a_attachment['name'];
$a_part['disposition'] = array ('filename' => $a_attachment['name']);
$a_part['type.parameters'] = array('name' => $a_attachment['name']);
$a_part["contents.data"] = $a_attachment['data'];
$a_body[] = $a_part;
}
// Create message in the draft box
$o_message = imap_mail_compose($a_header, $a_body);
$b_result = imap_append($this->o_mailbox, $o_company->draftbox, $o_message);

Zend registry mail sender : How to debug?

Mail doesn't get sent properly. I need to help to properly debug as to why it isn't working on the server. Any solution?
$config = new Zend_Config_Ini(APPLICATION_PATH.'/configs/application.ini', APPLICATION_ENV);
$mailer = Zend_Registry::get('mailer');
if ($to) {
$mailer->setsendBcc(true);
}
// Add admin emails as recipient.
$to[$config->email->to] = '';
$mailer->setTo($to);
$mailer->setTokens($mailParams);
$mailer->setTemplate($template);
$result = $mailer->send();
Zend_Registry only stores stuff (eg. objects). We don't know what object is '$mailer'. It's not standard Zend_Mail object. You would need to check it - get_class($mailer) or look for Zend_Registry::set('mailer'.
You can always try:
try{
$result = $mailer->send();
}catch(Exception $e){
echo $e->getMessage();
}
Edit:
Also check if you are setting recipient correctly. It looks a bit odd in your code.

How to change a pipe-forwarded email's "From" and "To" section in PHP

I am trying to mask emails. Basically give an email to a client like "RandomName#MyDomain.com" and have it forward "MyRealEmail#MyDomain.com".
I am pipe forwarding the emails to a php script on my server, where I want to use the "To" and "From" to find the real recipient of the message and forward the message to them removing any identifiable information from the Sender (From) section.
I can parse almost all the data right now from the header, but my problem is with the body. The html body portion can vary so much from different origins. Outlook have a <html> and <body> section, while Gmail just has <div>s. Regardless, I get these strange "=" signs in my raw email too, in both text and html sections, like <=div>!
I just want to change the "From" and "To" and keep the rest of the email pretty much exactly as it is so it doesn't have anomalies in its text or html section.
How can I do this? Should I just parse the raw email and change the occurrences of the emails? how can I send it then? or should I remake the email using phpmailer or some other class? how can i get the body correct then?
My hosting provider doesn't have MailParse extension installed, since I have seen some solutions on the site using that extension, so I am having to do this using available extensions in PHP 5.5
UPDATE
I managed to figure out the = issue, it was quoted-printable, so now I am calling quoted_printable_decode() to resolve that issue. Still trying to figure the best way to forward the email after altering the header though.
After a lot of failed attempts, finally have a solution I can live with. The host server didn't want to allow MailParse because it was an issue on their shared hosting environment, so I went with Mail_mimeDecode and Mail_MIME PEAR extensions.
// Read the message from STDIN
$fd = fopen("php://stdin", "r");
$input = "";
while (!feof($fd)) {
$input .= fread($fd, 1024);
}
fclose($fd);
$params['include_bodies'] = true;
$params['decode_bodies'] = true;
$params['decode_headers'] = true;
$decoder = new Mail_mimeDecode($input);
$structure = $decoder->decode($params);
// get the header From and To email
$From = ExtractEmailAddress($structure->headers['from'])[0];
$To = ExtractEmailAddress($structure->headers['to'])[0];
$Subject = $structure->headers['subject'];
ExtractEmailAddress uses a solution from "In PHP, how do I extract multiple e-mail addresses from a block of text and put them into an array?"
For the Body I used the following to find the text and html portions:
$HTML = "";
$TEXT = "";
// extract email body details
foreach($structure as $K => $V){
if(is_array($V)){
foreach($V as $KK => $VV){
if(is_object($VV)){
$bodyHTML = false;
$bodyPLAIN = false;
foreach($VV as $KKK => $VVV){
if(!is_array($VVV)){
if($KKK === 'ctype_secondary'){
if($VVV === 'html') { $bodyHTML = true; }
if($VVV === 'plain') { $bodyPLAIN = true; }
}
if($KKK === 'body'){
if($bodyHTML){
$bodyHTML = false;
$HTML .= quoted_printable_decode($VVV);
}
if($bodyPLAIN){
$bodyPLAIN = false;
$TEXT .= quoted_printable_decode($VVV);
}
}
}
}
}
}
}
}
Finally, I had the parts I needed so I used Mail_MIME to get the message out. I do my database lookup logic here and find the real destination and masked From email address using the From and To I extracted from the header.
$mime = new Mail_mime(array('eol' => "\r\n"));
$mime->setTXTBody($TEXT);
$mime->setHTMLBody($HTML);
$mail = &Mail::factory('mail');
$hdrs = array(
'From' => $From,
'Subject' => $Subject
);
$mail->send($To, $mime->headers($hdrs), $mime->get());
I don't know if this will cover all cases of email bodies, but since my system is not using attachments I am ok for now.
Take not of quoted_printable_decode(), that how I fixed the issue with the = in the body.
The only issue is the delay in mail I am having now, but I'll deal with that

Swift-Mailer error, "Address in mailbox given [] does not comply with RFC"

I have built a simple PHP contact form that is supposed to send mail trough the Swift-Mailer script.
Problem is I keep getting this error
Uncaught exception
'Swift_RfcComplianceException' with
message 'Address in mailbox given []
does not comply with RFC 2822, 3.6.2.'
Which I guess means I am using an invalid e-mail address. But since I am using myaddress#gmail.com to test the scrip the problem is probably somewhere else. This is my configuration:
Where the mail is sent to:
$my_mail = 'mymail#mydomain.com';
$my_name = 'My Name';
The content of the message:
$name = trim($_POST['name']);
$email = trim($_POST['email']);
$message = trim($_POST['message']);
$date = date('d/m/Y H:i:s');
$ipaddress = $_SERVER['REMOTE_ADDR'];
$content = $message.'\n\nSent on: '.$date.' From: '.$ipaddress;
The function i use to send the mail using swiftmailer:
function send_mail () {
require('/path/to/swift_required.php');
//The means of transport
$transport = Swift_SmtpTransport::newInstance('mail.mydomain.com', 25);
$transport->setUsername('myusername');
$transport->setPassword('mypass');
$mailer = Swift_Mailer::newInstance($transport);
//The message
$mail = Swift_Message::newInstance();
$mail->setSubject('Hello');
$mail->setFrom(array($email => $name ));
$mail->setTo(array($my_mail => $my_name));
$mail->setBody($content, 'text/plain');
//Sending the message
$test = $mailer->send($mail);
if ($test) {
echo '<p>Thank you for contacting us '.$name.'! We will get in touch soon.</p>';
}
else {
echo '<p>Something went wrong. Please try again later.</p>';
}
}
As you can see it is really simple form with three fields, name, mail and message. I also have other validation set up for each of contact form fields, but I think it is of little concern here.
Thank you for the help.
Edit:
Just test with using gmail as the smtp server. Unfortunately it still gives the same exact results.
All your data variables (addresses, names...) appear to be global. Global variables cannot be read from within functions unless you pass them as parameters (the recommended way) or use the global keyword (or the $GLOBALS array).

Categories