How to send email with text/plain, text/html and attaches in zf2 ?
I use this code to send email with smtp:
$files = $this->params()->fromFiles();
$smtp = new \Zend\Mail\Transport\Smtp();
$smtp->setAutoDisconnect(true);
$optn = new \Zend\Mail\Transport\SmtpOptions(array(
'host' => 'mail.myserver.com',
'connection_class' => 'login',
'connection_config' => array(
'username' => 'user#myserver.com',
'password' => 'mypassword',
),
));
$smtp->setOptions($optn);
$htmlPart = new \Zend\Mime\Part('<p>some html</p>');
$htmlPart->type = Mime::TYPE_HTML;
$textPart = new \Zend\Mime\Part('some text');
$textPart->type = Mime::TYPE_TEXT;
$i=0;
$attaches = array();
foreach($files as $file){
if ($file['error'])
continue;
$attaches[$i] = new \Zend\Mime\Part(file_get_contents($file['tmp_name']));
$attaches[$i]->type = $file['type'].'; name="'.$file['name'].'"';
$attaches[$i]->encoding = 'base64';
$attaches[$i]->disposition = 'attachment';
$attaches[$i]->filename = $file['name'];
$i++;
}
$parts = array();
if (count($attaches)>0) {
$parts = array_merge(array($textPart,$htmlPart),$attaches);
$type = Mime::MULTIPART_MIXED;
}
else{
$parts = array($textPart, $htmlPart);
$type = Mime::MULTIPART_ALTERNATIVE ;
}
$body = new \Zend\Mime\Message();
$body->setParts($parts);
$message = new \Zend\Mail\Message();
$message->setFrom('user#myserver.com');
$message->addTo('receiver#myserver.com');
$message->setSubject('subject');
$message->setEncoding("UTF-8");
$message->setBody($body);
$message->getHeaders()->get('content-type')->setType($type);
$smtp->send($message);
If I attach files, it sends files and contents but it shows plain and html text together in receiver inbox:
<p>some html</p>
some text
When I don't attach any files, it shows html text singly:
some html
Any help?
Currently there is no easy way in ZF2 (2.2) to combine a multipart/alternative body (html with text alternative for clients that cannot/do-not-want-to use html) with attachments.
If you add the 'multipart/alternative' content-type header to the entire message, in some email clients the attachment (link) will not be displayed.
The solution is to split the message in two, the body (text and html) and the attachment:
http://jw-dev.blogspot.com.es/2013/01/zf2-zend-mail-multipartalternative-and.html
an example:
$content = new MimeMessage();
$htmlPart = new MimePart("<html><body><p>Sorry,</p><p>I'm going to be late today!</p></body></html>");
$htmlPart->type = 'text/html';
$textPart = new MimePart("Sorry, I'm going to be late today!");
$textPart->type = 'text/plain';
$content->setParts(array($textPart, $htmlPart));
$contentPart = new MimePart($content->generateMessage());
$contentPart->type = 'multipart/alternative;' . PHP_EOL . ' boundary="' . $content->getMime()->boundary() . '"';
$attachment = new MimePart(fopen('/path/to/test.pdf', 'r'));
$attachment->type = 'application/pdf';
$attachment->encoding = Mime::ENCODING_BASE64;
$attachment->disposition = Mime::DISPOSITION_ATTACHMENT;
$body = new MimeMessage();
$body->setParts(array($contentPart, $attachment));
$message = new Message();
$message->setEncoding('utf-8')
->addTo('mywife#home.com')
->addFrom('myself#office.com')
->setSubject('will be late')
->setBody($body);
$transport = new SmtpTransport();
$options = new SmtpOptions($transportConfig),
));
$transport->setOptions($options);
$transport->send($message);
For the above you would need the following use statements:
use Zend\Mail\Message;
use Zend\Mail\Transport\Smtp as SmtpTransport;
use Zend\Mail\Transport\SmtpOptions;
use Zend\Mime\Mime;
use Zend\Mime\Part as MimePart;
use Zend\Mime\Message as MimeMessage;
ZF1 had a _buildBody() method in Zend_Mail_Transport_Abstract which did this automatically.
I have found it a better solution so I am writing it.
Namespace YourNamesapace;
use Zend\Mail\Message as ZendMessage;
use Zend\Mime\Part as MimePart;
use Zend\Mime\Message as MimeMessage;
use Zend\Mail\Transport\Sendmail;
class Testmail
{
public static function sendMailWithAttachment($to, $subject, $htmlMsg, $dir, $fileName)
{
$fileFullPath = $dir . '/' . $fileName;
// Render content from template
$htmlContent = $htmlMsg;
// Create HTML part
$htmlPart = new MimePart($htmlContent);
$htmlPart->type = "text/html";
// Create plain text part
$stripTagsFilter = new \Zend\Filter\StripTags();
$textContent = str_ireplace(array("<br />", "<br>"), "\r\n", $htmlContent);
$textContent = $stripTagsFilter->filter($textContent);
$textPart = new MimePart($textContent);
$textPart->type = "text/plain";
// Create separate alternative parts object
$alternatives = new MimeMessage();
$alternatives->setParts(array($textPart, $htmlPart));
$alternativesPart = new MimePart($alternatives->generateMessage());
$alternativesPart->type = "multipart/alternative;\n boundary=\"".$alternatives->getMime()->boundary()."\"";
$body = new MimeMessage();
$body->addPart($alternativesPart);
$attachment = new MimePart( file_get_contents($fileFullPath) );
$attachment->type = \Zend\Mime\Mime::TYPE_OCTETSTREAM;
$attachment->filename = basename($fileName);
$attachment->disposition = \Zend\Mime\Mime::DISPOSITION_ATTACHMENT;
$attachment->encoding = \Zend\Mime\Mime::ENCODING_BASE64;
$body->addPart($attachment);
// Create mail message
$mailMessage = new ZendMessage();
$mailMessage->setFrom('noreply#example.com', 'from Name');
$mailMessage->setTo($to);
$mailMessage->setSubject($subject);
$mailMessage->setBody($body);
$mailMessage->setEncoding("UTF-8");
$mailMessage->getHeaders()->get('content-type')->setType('multipart/mixed');
$transport = new Sendmail();
$transport->send($mailMessage);
}
}
Set the type from :
$attaches[$i]->type = $file['type'].'; name="'.$file['name'].'"';
To:
$attaches[$i]->type = \Zend\Mime\Mime::TYPE_OCTETSTREAM;
You will also want to confirm that if you are using an SMTP service that they allow attachements through the protocol.
E-Mail Messages with Attachments
$mail = new Zend\Mail\Message();
// build message...
$mail->createAttachment($someBinaryString);
$mail->createAttachment($myImage,
'image/gif',
Zend\Mime\Mime::DISPOSITION_INLINE,
Zend\Mime\Mime::ENCODING_BASE64);
If you want more control over the MIME part generated for this attachment you can use the return value of createAttachment() to modify its attributes. The createAttachment() method returns a Zend\Mime\Part object:
$mail = new Zend\Mail\Message();
$at = $mail->createAttachment($myImage);
$at->type = 'image/gif';
$at->disposition = Zend\Mime\Mime::DISPOSITION_INLINE;
$at->encoding = Zend\Mime\Mime::ENCODING_BASE64;
$at->filename = 'test.gif';
$mail->send();
An alternative is to create an instance of Zend\Mime\Part and add it with addAttachment():
$mail = new Zend\Mail\Message();
$at = new Zend\Mime\Part($myImage);
$at->type = 'image/gif';
$at->disposition = Zend\Mime\Mime::DISPOSITION_INLINE;
$at->encoding = Zend\Mime\Mime::ENCODING_BASE64;
$at->filename = 'test.gif';
$mail->addAttachment($at);
$mail->send();
Reference1
Reference2
Reference3
Related
I trying to make a php script to send one message to other person in moodle.
I've seen the message api and i make this
$message = new \core\message\message();
$message->component = 'moodle';
$message->name = 'instantmessage';
$message->userfrom = 318;
$message->userto = 323;
$message->subject = 'message subject 1';
$message->fullmessage = 'message body';
$message->fullmessageformat = FORMAT_MARKDOWN;
$message->fullmessagehtml = '<p>message body</p>';
$message->smallmessage = 'small message';
$message->notification = '0';
$message->contexturl = 'http://GalaxyFarFarAway.com';
$message->contexturlname = 'Context name';
$message->replyto = "random#example.com";
$content = array('*' => array('header' => ' test ', 'footer' => ' test ')); // Extra content for specific processor
$message->set_additional_content('email', $content);
$message->courseid = 107; // This is required in recent versions, use it from 3.2 on https://tracker.moodle.org/browse/MDL-47162
$messageid = message_send($message)
The problem is, when the user 323 send a reply message in the chat that is created in the moodle internal messaging, an error occurs (the message is surrounded by red) and never arrives.
And I really want it to be able to respond as if it were a normal conversation.
I don't know if I'm going wrong.
Thank you
I finally found it !!!
The problem is that first you have to create a conversation between the users and then send the message
if(!\core_message\api::get_conversation_between_users([$userfrom, $userto ])){
$conversation = \core_message\api::create_conversation(
\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
[
$userfrom,
$userto
]
);
}
$message = new \core\message\message();
$message->component = 'moodle';
$message->name = 'instantmessage';
$message->userfrom = $userfrom ;
$message->userto = $userto;
$message->subject = 'Nuevo mensaje';
$message->fullmessage = $msg;
$message->fullmessageformat = FORMAT_MARKDOWN;
$message->fullmessagehtml = $msg;
$message->smallmessage = $msg;
$message->notification = '0';
$message->contexturl = '';
$message->contexturlname = 'Context name';
$message->replyto = "##########.###";
$content = array('*' => array('header' => '', 'footer' => ''));
$message->set_additional_content('email', $content);
$message->courseid = 107;
message_send($message);
It might be because the userto and userfrom need to be objects eg:
$userto = $DB->get_record('user', array('id' => 323));
$message->userfrom = $USER; // Current user.
$message->userto = $userto;
see https://docs.moodle.org/dev/Message_API#How_to_send_a_message
I have a custom fuction to parse incoming emails and their attachements. Of course one email may contain multiple attachement.
I have this code:
public function parseEmail() {
// read from stdin
$fd = fopen("php://stdin", "r");
$rawEmail = "";
while (!feof($fd)) {
$rawEmail .= fread($fd, 1024);
}
fclose($fd);
$parser = new Parser();
$parser->setText($rawEmail);
$email = new Email;
$email->to = $parser->getHeader('to');
$email->from = $parser->getHeader('from');
$email->subject = $parser->getHeader('subject');
$email->body_text = $parser->getMessageBody('text');
$attachments = $parser->getAttachments();
$filesystem = new Filesystem;
foreach ($attachments as $attachment) {
$filesystem->put(public_path() . '/uploads/' . $attachment->getFilename(), $attachment->getContent());
$email->attachement()->name = $attachment->getFilename();
}
$email->save();
}
Now this code can store only one attachement. But how can I update to store multiple attachements in model?
You can change this line $email->attachement()->name = $attachment->getFilename(); to $email->attachement()->name[] = $attachment->getFilename(); for pushing to array all attachments, after that you can serialize it and save, if this ok for businesses logic.
I created an image with php imagecreate and I want to send it through e-mail with PHPMailer, but I don't understand which method I have to use and how
include 'Barcode39.php';
include 'PHPMailer.php';
$bar = new Barcode39('10127');
$bar->barcode_text_size = 10;
$bar->barcode_bar_thick = 10;
$bar->barcode_bar_thin = 5;
$bar_img = $bar->draw();
$bar_size[0] = imagesx($bar_img);
$bar_size[1] = imagesy($bar_img);
$im = imagecreatefromjpeg('biglietto.jpg');
imagecopymerge($im, $bar_img, 10, 9, 0, 0, $bar_size[0], $bar_size[1], 100);
$email = new PHPMailer();
$email->From = 'myemail#email.com';
$email->Body = 'my email';
$email->AddAddress( 'myemail#email.com' );
$email->addAttachment($im??);
From documentation:
addAttachment(string $path, string $name = '', string $encoding = 'base64', string $type = '', string $disposition = 'attachment') : boolean
Just provide string path to your file and you will be good.
We have a script that monitors the database. In the database JSON data and fromName and fromEmail are stored. If the handledAt timestamp is null the email still has to be send. So we have created a cronjob that monitors the handledAt column. If it is null the email should be sent.
Our scripts works fine, however it is a bit slow. Therefore I was wondering if we are doing it in a proper manner.
Grab All emails that need to be sent
foreach($ResultSelectEmails AS $key => $value)
{
require_once '../library/Twig/Autoloader.php';
Twig_Autoloader::register();
$loader = new Twig_Loader_String();
$twig = new Twig_Environment($loader, array(
'cache' => '../tmp/cache/'
));
$Contents = $twig->render(stripslashes($Templ['templateHTML']), $EData);
$Subject = $twig->render(stripslashes($Templ['templateSubject']), $EData);
$WriteFile = fopen('logs/'.$PDFLogFile.'.html','w');
fwrite($WriteFile, $Contents);
fclose($WriteFile);
// Create the Transport
$transport = Swift_SmtpTransport::newInstance('mail.example.com', 25)
->setUsername('info#example.com')
->setPassword('examplePassword')
;
// Create the Mailer using your created Transport
$mailer = Swift_Mailer::newInstance($transport);
$message = Swift_Message::newInstance($Subject)
->setFrom(array($ResultSelectEmails[$key]['fromEmail'] => $ResultSelectEmails[$key]['fromName']))
->setTo(array($ResultSelectEmails[$key]['toEmail']))
->setBody($Contents, 'text/html', 'UTF-8')
;
if(isset($EmailAttachements))
{
foreach($EmailAttachements AS $key => $value)
$message->attach(Swift_Attachment::fromPath($value));
}
$result = $mailer->send($message);
}
In the script we create a separate transport for each email. Sometimes the mail server throws an error. Mainly that it can't login.
Can we improve the script performance?
Looking forward to your thoughts....
I see some calls that you shouldn't do in a foreach loop. I don't know how many mails you want to send but this is not optimal. As you're not processing the loop in parallel you can move a few lines outside which should prevent creating some instances over and over again. I don't know the exact purpose of your code and without any details it's hard to say if this is a noticable improvement, but you could give it a try:
require_once '../library/Twig/Autoloader.php';
Twig_Autoloader::register();
$loader = new Twig_Loader_String();
$twig = new Twig_Environment($loader, array(
'cache' => '../tmp/cache/'
));
// Create the Transport
$transport = Swift_SmtpTransport::newInstance('mail.example.com', 25)
->setUsername('info#example.com')
->setPassword('examplePassword')
;
// Create the Mailer using your created Transport
$mailer = Swift_Mailer::newInstance($transport);
foreach ($ResultSelectEmails AS $key => $value) {
$Contents = $twig->render(stripslashes($Templ['templateHTML']), $EData);
$Subject = $twig->render(stripslashes($Templ['templateSubject']), $EData);
$WriteFile = fopen('logs/' . $PDFLogFile . '.html', 'w');
fwrite($WriteFile, $Contents);
fclose($WriteFile);
$message = Swift_Message::newInstance($Subject)
->setFrom(array($ResultSelectEmails[$key]['fromEmail'] => $ResultSelectEmails[$key]['fromName']))
->setTo(array($ResultSelectEmails[$key]['toEmail']))
->setBody($Contents, 'text/html', 'UTF-8')
;
if (isset($EmailAttachements)) {
foreach ($EmailAttachements AS $key => $value)
$message->attach(Swift_Attachment::fromPath($value));
}
$result = $mailer->send($message);
}
I can send a test mail with Zend Mail with a Attachement. This works fine.
Like this:
$mail = new Zend_Mail();
$mail->setFrom('test#test333.ch', 'test#test333.ch');
$mail->addTo('test#test333.ch444', 'Test');
$at = $mail->createAttachment($fileContents);
$at->type = 'image/gif';
$at->disposition = Zend_Mime::DISPOSITION_INLINE;
$at->encoding = Zend_Mime::ENCODING_BASE64;
$at->filename = 'test.gif';
$mail->setSubject(
'Hi'
);
$mail->setBodyText('...Your message here...');
$mail->send($transport);
}
Now i will add a extra Content-Type which I can read later. like this:
Content-Type:test/test-test
How can I do that with ZF1?
Try with:
$mail->addHeader('Content-Type', 'test/test-test');
$mail->send($transport);