I have a problem with Swift Mailer, It seems easy, but I'm strugling with it for hours.
I need to send an email to multiple recipients.
This is a string I begin with (the content of $email->getRecipients() ):
// Just an example
first#gmail.com, second#gmail.com
First I remove all non-visible characters:
$string = preg_replace('/[\x00-\x1F\x7F]/u', '', $email->getRecipients());
Then I add surranding quotes:
$addQuotes = "'" . str_replace(",", "','", $string) . "'";
And remove empty spaces:
$recipients = str_replace(' ', '', $addQuotes);
Which gives me:
'first#gmail.com','second#gmail.com'
If I paste the string manually:
->setTo(['first#gmail.com','second#gmail.com'])
It works. But when I try to put variable like this:
$array = explode(',', $recipients);
...
->setTo($array)
Emails are not being sent.
When I do this:
->setTo([$recipients])
I get the error Address in mailbox given ['...','...'] does not comply with RFC 2822, 3.6.2.
I also tried:
foreach($array as $recipient) {
$message->setTo($recipient);
$this->get('mailer')->send($message);
}
Not working! But again, if I paste string directly, it works:
foreach($array as $recipient) {
$message->setTo('first#gmail.com');
$this->get('mailer')->send($message);
}
The code:
private function sendEmail($email)
{
//$email->getRecipients() = 'first#gmail.com, second#gmail.com'
$string = preg_replace('/[\x00-\x1F\x7F]/u', '', $email->getRecipients());
$addQuotes = "'" . str_replace(",", "','", $string) . "'";
$recipients = str_replace(' ', '', $addQuotes);
$array = explode(',', $recipients);
$message = \Swift_Message::newInstance()
->setSubject($email->getSubject())
->setFrom($email->getSender())
->setTo($array)
->setBody(
$this->renderView(
'Emails/default.html.twig',
array('body' => $email->getBody())
),
'text/html'
);
//foreach($array as $recipient) {
// $message->setTo($recipient);
// $this->get('mailer')->send($message);
//}
$this->get('mailer')->send($message);
}
Related
How to format Whatsapp Web Message ?
I trying replacing tags like this :
$nl = "%0D%0A";
$space = "%20";
$MSG = nl2br($MSG);
$MSG = str_replace( array("<b>","<bold>","</b>","</bold>"), array("*","*","*","*"), $MSG);
$MSG = str_replace( array(" ","<br>","\n", "\r\n"), array($space,$nl,$nl,$nl), $MSG);
I tried using urlencode, htmlspecialchars and nothing.
I´m receiving on https://api.whatsapp.com/send?phone=XXX&text=MSG a totally unformated and with a lot of chars string. Like this :
%F0%9F%94%94%2A...
I found the error and I´m posting here to help others.
// Should use UTF8
$MSG = utf8_encode($MSG);
// Whatsapp patterns
$nl = "%0D%0A"; // newline
$space = "%20"; // space
// Replace some Whatstapp tags
$MSG = str_replace( array("<b>","<bold>","</b>","</bold>"), array("*","*","*","*"), $MSG);
// Replace newline to Whatsapp format
$MSG = str_replace( array(" ","<br>","\n", "\r\n"), array($space,$nl,$nl,$nl), $MSG);
I replace only BOLD but you can add others tags. See :
https://faq.whatsapp.com/general/chats/how-to-format-your-messages/?lang=en
I'm trying to send a json object as a POST command using the following:
$uri = "http://amore-luce.com/product_create";
$product = $observer->getEvent()->getProduct();
$json = Mage::helper('core')->jsonEncode($product);
Mage::log(" Json={$json}", null,'product-updates.txt');
// new HTTP request to some HTTP address
$client = new Zend_Http_Client('http://amore-luce.com/product_create');
// set some parameters
$client->setParameterPost('product', $json);
// POST request
$response = $client->request(Zend_Http_Client::POST);
When I view the $json the data is there and all looks good - however the POST is not sending the json data. I'm capturing it using a simple email form that should send me the response:
<?php
$webhookContent = "";
$ref = "";
$webhook = fopen('php://input' , 'rb');
while (!feof($webhook)) {
$webhookContent .= fread($webhook, 4096);
}
fclose($webhook);
$headers = array();
foreach($_SERVER as $key => $value) {
if (substr($key, 0, 5) <> 'HTTP_') {
continue;
}
$header = str_replace(' ', '-', ucwords(str_replace('_', ' ', strtolower(substr($key, 5)))));
$headers[$header] = $value;
}
foreach ($headers as $header => $value) {
$ref .= "$header: $value <br />\n";
}
$post = file_get_contents('php://input');
$to = "address#my-email.com"; //the address the email is being sent to
$subject = "This is the subject"; //the subject of the message
$msg = "This is the message - Webhook content: ".$webhookContent." This is url: ".$ref; //the message of the email
mail($to, $subject, $msg, 'From: PHP Scriptv2 <noreply#domain.com>'); //send the email.
echo ($_SERVER['HTTP_REFERER']."<br>".$_SERVER['REQUEST_URI']);
?>
This page works with other json POST requests I've sent to it. I'm fairly new at sending POST requests so any help would be greatly appreciated.
Try change :
$client->setParameterPost('product', $json);
to :
$client->setHeaders('Content-type','application/json');
$client->setParameterPost('product', $json);
or use:
$client->setRawData($json, 'application/json');
So Update / Answer changing how I did it to these lines of code:
$uri = "http://requestb.in/p6p4syp6";
$product = $observer->getEvent()->getProduct();
$json = Mage::helper('core')->jsonEncode($product);
Mage::log(" Json={$json}", null,'product-updates.txt');
$client = new Zend_Http_Client($uri);
$client->setRawData($json, null)->request('POST');
Changing the SetRawData($json, null) was the bit - using SetRawDate($json, 'application/json') caused it to fail.
Thanks Voodoo417 - I'll also try your suggestion and see if that lets me set the correct type
i don't understand how send one email for all users, i do it this in my controller :
// Init
$data = $this->request->data['Email'];
$d = array(
'subject' => $data['subject'],
'message' => $data['message']
);
// QUERY
$all = $this->Spoutnik->find('all', array(
'conditions' => array(
'Spoutnik.role >=' => '1'
),
'fields' => array('Spoutnik.email')
));
$this->set(compact('all'));
// list
$bcc = '';
foreach ($all as $user) {
$bcc .= $user['Spoutnik']['email'].',';
}
// MAIL
App::uses('CakeEmail', 'Network/Email');
$CakeEmail = new CakeEmail('default');
$website_short_name = Configure::read('website.short_name');
$CakeEmail->bcc("$bcc");
$CakeEmail->subject(''.$website_short_name.' :: '.$d['subject'].'');
$CakeEmail->viewVars(array(
'message' => (''.$d['message'].'')
));
$CakeEmail->emailFormat('html');
$CakeEmail->template('message_direct');
// final
$CakeEmail->send();
But i have error "no valid mail" , and after the liste of user's mail
what is wrong in my code ?
Couple of things I've noticed at a quick glance...
foreach ($all as $user) {
$bcc .= $user['Spoutnik']['email'].',';
}
In that code, you're adding a comma after every email, so at the end of your string you'll have a comma. Try this:
$e = 0;
foreach ($all as $user) {
if($e > 0) $bcc .= ',';
$bcc .= $user['Spoutnik']['email'];
$e++;
}
--edit-- good point Deepak, Cake's documentation suggests you give BCC an array. It's easier and more efficient to produce so do that.
Second, $CakeEmail->bcc("$bcc"); doesn't need the quotes. It should work fine with them, but I've seen Cake do some pretty weird things... Try taking them out:
$CakeEmail->bcc($bcc);
Third, you're setting all those emails to BCC which is fine, but I can't see a to address. If you want to send out to a lot of email address without them seeing each other, you still need to send the email to somewhere, even if its noreply#yourdomain.com. Add a to address in before you send:
$CakeEmail->to('noreply#yourdomain.com');
I will just use the addBcc function of CakeEmail and modify the loop:
App::uses('CakeEmail', 'Network/Email');
$CakeEmail = new CakeEmail('default');
// list
foreach ($all as $user) {
$CakeEmail->addBcc($user['Spoutnik']['email']);
}
$website_short_name = Configure::read('website.short_name');
$CakeEmail->subject(''.$website_short_name.' :: '.$d['subject'].'');
$CakeEmail->viewVars(array(
'message' => (''.$d['message'].'')
));
Try changing your $bcc block to this:
// list
$bcc = array();
foreach ($all as $user) {
$bcc[]= $user['Spoutnik']['email'];
}
Also refer to CakeEmail Documentation
I have this very simple url bbcoder which i wish to adjust so if the linked does not contain http:// to add it in, how can i do this?
$find = array(
"/\[url\=(.+?)\](.+?)\[\/url\]/is",
"/\[url\](.+?)\[\/url\]/is"
);
$replace = array(
"$2",
"$1"
);
$body = preg_replace($find, $replace, $body);
You can use a (http://)? to match the http:// if exists, and ignore the group result in 'replace to' pattern and use your own http:// , like this:
$find = array(
"/\[url\=(http://)?(.+?)\](.+?)\[\/url\]/is",
"/\[url\](http://)?(.+?)\[\/url\]/is"
);
$replace = array(
"$3",
"$2"
);
$body = preg_replace($find, $replace, $body);
if(strpos($string, 'http://') === FALSE) {
// add http:// to string
}
// I've added the http:// in the regex, to make it optional, but not remember it,
// than always add it in the replace
$find = array(
"/\[url\=(?:http://)(.+?)\](.+?)\[\/url\]/is",
"/\[url\](.+?)\[\/url\]/is"
);
$replace = array(
"$2",
"http://$1"
);
$body = preg_replace($find, $replace, $body);
If you would use a callback function and preg_replace_callback(), you can use something like this:
You can do that this way. It will always add 'http://', and than the string without 'http://'
$string = 'http://'. str_replace('http://', '', $string);
We have a custom php email marketing app, and an interesting problem:
If the subject line of the message contains a word with accents, it 'swallows' the spaces between it and the following word.
An example: the phrase
Ángel Ríos escucha y sorprende
is shown (by at least gmail and lotus notes) as
ÁngelRíos escucha y sorprende
The particular line in the message source shows:
Subject: =?ISO-8859-1?Q?=C1ngel?= =?ISO-8859-1?Q?R=EDos?= escucha y sorprende
(semi-full headers):
Delivered-To: me#gmail.com
Received: {elided}
Return-Path: <return#path>
Received: {elided}
Received: (qmail 23734 invoked by uid 48); 18 Aug 2009 13:51:14 -0000
Date: 18 Aug 2009 13:51:14 -0000
To: "Adriano" <me#gmail.com>
Subject: =?ISO-8859-1?Q?=C1ngel?= =?ISO-8859-1?Q?R=EDos?= escucha y sorprende
MIME-Version: 1.0
From: {elided}
X-Mailer: PHP
X-Lista: 1290
X-ID: 48163
Content-Type: text/html; charset="ISO-8859-1"
Content-Transfer-Encoding: quoted-printable
Message-ID: <kokrte.rpq06m#example.com>
EDIT:
The app uses an old version of Html Mime Mail to prepare messages, I'll try to upgrade to a newer version. Anyway, this is the function that encodes the subject:
/**
* Function to encode a header if necessary
* according to RFC2047
*/
function _encodeHeader($input, $charset = 'ISO-8859-1')
{
preg_match_all('/(\w*[\x80-\xFF]+\w*)/', $input, $matches);
foreach ($matches[1] as $value) {
$replacement = preg_replace('/([\x80-\xFF])/e', '"=" . strtoupper(dechex(ord("\1")))', $value);
$input = str_replace($value, '=?' . $charset . '?Q?' . $replacement . '?=', $input);
}
return $input;
}
And here it's the code where the subject is encoded:
if (!empty($this->headers['Subject'])) {
$subject = $this->_encodeHeader($this->headers['Subject'],
$this->build_params['head_charset']);
unset($this->headers['Subject']);
}
Wrap-up
The problem was that, indeed, the program wasn't encoding the space in the case mentioned. The accepted answer solved my problem, after a slight modification (mentioned in the comments to that answer) because the installed version of PHP didn't support a particular implementation detail.
Final answer
Although the accepted answer did solve the problem, we found that it, combined with many thousands of emails, was chewing all the available memory on the server. I checked the website of the original developer of this email framework, and found that the function had been updated to the following:
function _encodeHeader($input, $charset = 'ISO-8859-1') {
preg_match_all('/(\w*[\x80-\xFF]+\w*)/', $input, $matches);
foreach ($matches[1] as $value) {
$replacement = preg_replace('/([\x80-\xFF])/e', '"=" . strtoupper(dechex(ord("\1")))', $value);
$input = str_replace($value, $replacement , $input);
}
if (!empty($matches[1])) {
$input = str_replace(' ', '=20', $input);
$input = '=?' . $charset . '?Q?' .$input . '?=';
}
return $input;
}
which neatly solved the problem and stayed under the mem limit.
You need to encode the space in between as well (see RFC 2047):
(=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?=) (ab)
White space between adjacent 'encoded-word's is not displayed.
[…]
(=?ISO-8859-1?Q?a_b?=) (a b)
In order to cause a SPACE to be displayed within a portion of encoded text, the SPACE MUST be encoded as part of the 'encoded-word'.
(=?ISO-8859-1?Q?a?= =?ISO-8859-2?Q?_b?=) (a b)
In order to cause a SPACE to be displayed between two strings of encoded text, the SPACE MAY be encoded as part of one of the 'encoded-word's.
So this should do it:
Subject: =?ISO-8859-1?Q?=C1ngel=20R=EDos?= escucha y sorprende
Edit Try this function:
function _encodeHeader($str, $charset='ISO-8859-1')
{
$words = preg_split('/(\s+)/', $str, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
$func = create_function('$match', 'return $match[0] === " " ? "_" : sprintf("=%02X", ord($match[0]));');
$encoded = false;
foreach ($words as $key => &$word) {
if (!ctype_space($word)) {
$tmp = preg_replace_callback('/[^\x21-\x3C\x3E-\x5E\x60-\x7E]/', $func, $word);
if ($tmp !== $word) {
if (!$encoded) {
$word = '=?'.$charset.'?Q?'.$tmp;
} else {
$word = $tmp;
if ($key > 0) {
$words[$key-1] = preg_replace_callback('/[^\x21-\x3C\x3E-\x5E\x60-\x7E]/', $func, $words[$key-1]);
}
}
$encoded = true;
} else {
if ($encoded) {
$words[$key-2] .= '?=';
}
$encoded = false;
}
}
}
if ($encoded) {
$words[$key] .= '?=';
}
return implode('', $words);
}
add
$input = str_replace('?', '=3F', $input);
in this fragment:
if (!empty($matches[1])) {
$input = str_replace('?', '=3F', $input);
$input = str_replace(' ', '=20', $input);
$input = '=?' . $charset . '?Q?' .$input . '?=';
}
Look up mbstring and UTF conversions. Many of the special characters in non-English languages are dealt with in the UTF8 character set.
Converting your subject string to UTF8 and ensuring that the email is sent as such should render the subject lines correctly.
At least it did for us when we had a similar issue sending email
It would appear you'd better send Subject: =?ISO-8859-1?Q?=C1ngel R=EDos escucha y sorprende?= , as the problem appears near the ?= encoding end.