Im trying to send multiple emails with Sendgrid, and everything works fine, unless i change Content type meanwhile.
Is it possible to change contentType determined which email im sending to?
The error:
{"message":"If present, text/plain and text/html may only be provided once.","field":"content","help":null}]
Code:
foreach ($emailAddress as $key => $email) {
$addresses["$email"] = "$key";
$perzon = new Personalization();
$perzon->addTo(new To((trim($email))));
$mail->addPersonalization($perzon);
if ($email == "example#example.org" || $email == "iexample2#example2.org") {
$mail->addContent(
"text/plain",
str_replace(" ", "", $messagePlain)
);
$mail->setSubject($subject);
} else {
$mail->addContent(
"text/html",
nl2br($message)
);
$mail->setSubject($subject);
}
}
It looks like you're re-using the $mail object each time you loop. And addContent() adds extra content to the email (clue's in the name! :-)), it doesn't overwrite existing content. So by the time you're on the second email you could have added two lots of plaintext content (for example), and the mailing class can't cope with that because it doesn't know which version of the plaintext content you really want to send - an email cannot contain more than one version of the same kind of content (because if it did, again the receiving client wouldn't know which version to display either).
So wherever you are declaring the $mail object (it isn't shown in your question), you need to move that line inside your foreach loop and that should resolve the issue, because you'll have a fresh instance of the email object each time, instead of keep adding things to an existing one.
Also I'd expect you need to move the code which sends the email inside the loop too, otherwise it'll only send once (using whatever was the last settings generated by the loop).
Related
I am working on theapplication that fetches clients emails from DB, stores them in a array, loop through the array and send email to each client individually.
The problem occurred when PHPMailer is sending a double email to clients and also in and in one of emails "to" field contains both recepient address and in second email there is also a second clients emails as well.
I consider this as a vulnerability.
Here is my code:
$array = [ 0 => 'email#gmail.com' , 1 => 'email2#gmail.com' ]; //Example
foreach ($array as $key => $value) {
$mail->addAddress($value);
if (!$mail->send())
{
throw new Exception($mail->ErrorInfo);
} else
{
$mail->addAddress(NULL); //Attempt to unset
header('Location: ../public/email.php'); //Redirect to start page
}
}
So to sum it up: When this is run, it sends email to 'email#gmail.com' and 'email2#gmail.com'.
First email will get one copy of email.
Second email will get two copies of the same email, first with showing itself as recipient, and second one with itself recipient + other clients email.
I've tested this with only 2 fetched clients, with even more I guess there will be even more repetitions.
Thank you guys!
There are two problems here:
You are not removing the address from the mail, so when you add a second one, the first one is still there and both will see the other address.
You are using a header redirect in your loop without terminating your script. This can cause code after the redirect to run, but there is no guarantee for how much and how long.
The first problem you can solve by clearing the recipients at the end of the loop:
$mail->ClearAllRecipients();
As for the second problem, you should not redirect anywhere inside the loop and when you redirect after all messages have been sent, you should exit your scipt using exit; so that nothing gets executed after that.
I think you're re-using $value. Try using unset($value); see if it helps. You can also look here
Warning
Reference of a $value and the last array element remain even after the foreach loop. It is recommended to destroy it by unset(). Otherwise you will experience the following behavior:
I need some advice because I am building a subscription module. And I have a list of so many emails. Let say 1052 emails. And I have a code like this:
$email_list = $this->getClientEmails(); //all email for now returns 1052 valid emails
$valid_email = array();
$invalid_email = array();
if(count($email_list) > 0) {
for($x = 0; $x < count($email_list); $x++) {
if(valid_email($email_list[$x]['email'])) {
$valid_email[] = $email_list[$x]['email'];
}
//get all invalid emails
/*else {
$invalid_email[] = array(
'id' => $email_list[$x]['id'],
'email' => $email_list[$x]['email']
);
}*/
}
}
$email_string = implode(',', $valid_email);
$this->email->set_mailtype("html");
$this->email->from($from, 'Sample Admin');
$this->email->to($email_string); //send an email to 1052 users
$this->email->cc('test#sampleemail.com.ph');
$this->email->subject($subj);
$this->email->message($content);
$send_mail = $this->email->send();
if($send_mail) {
fp('success');
} else {
fp('failed');
}
Is it fine if I send an email like this? Or should I make a loop to send my email to different users? Means I will not use my imploded string. I will do the sending once in every week. And also what if the sending of email suddenly stops in the middle what should I do? Do I need to resend it again? Or should I make a column in my table that will update if the email is sent or not?
Can you give me some advice about this? That's all thanks.
Okay because you have a mailing list the first thing that i would recommend is that you push the script to background. Use selinium or cron for the same that way page render won't get stuck.
Once done You can send emails either way, send to multiple people or one at a time, both of them are valid and won't cause any problem. The point you need to consider here is the SMTP connection that you maintain.
If you are sending them all individually, you don't want to close connection to SMTP server and reconnect every time to send the mail which would only cause the overhead.
I should say that from your case the most valid way to send email is make a queue on some database preferably redis and have a task handle them in background (cron job if you are on cpanel or selinium if you own the server)
Finally this is a part that you might wanna test out. Because you have a mailing list i am guessing you don't want people to see through your whole list so check the headers when you are sending mails to all at once and if you don't see email from other users , you are good to go else send to each of them separately.
Also one final thing, emails not being delivered is usually bounced which may reflect bad on your server so have a script that flags emails that are constantly rejected and stop sending mails to the same or your ip address might end with bad repo and mails might end up in spam.
Have you thought of using PHPMailer as a library on your CodeIgniter installation?
You could just do it like this:
if(count($email_list) > 0) {
for($x = 0; $x < count($email_list); $x++) {
if(valid_email($email_list[$x]['email'])) {
$mail->addAddress($email_list[$x]['email'], $x);
}
}
}
Please refer to this example on how to use PHPMailer.
I hope this helps, or at least that it gives you a different perspective on how can this be done.
Referring to:
Or should I make a column in my table that will update if the email is sent or not?
Yes, I think that if you want to control if an email has been sent you should use a 1 character field on your table as a "flag" to corroborate that the email has been sent to your users.
I'm using the Zend_Mail_Message class to display emails inside of my PHP app, and am able to output the subject, content, date and even the NAME of the sender (using $message->from) but I can't figure out how to get the email address of the person who sent the message. The documentation is no help and googling finds a million results for how to send messages with Zend, but nothing about getting the address that sent the message.
EDIT:
This is how I ended up doing it. After some more digging, I found the sender's email in a field called 'return-path'. Unfortunately, this field has a dash in the name (WTF??) so to access it, I had to do this:
$return_path = 'return-path';
$message->reply_to = $zendMessage->$return_path;
Using the return-path caused some problems with some emails, specifically messages from no-reply accounts (mail-noreply#gmail.com, member#linkedin.com etc). These addresses would end up looking something like this:
m-9xpfkzulthmad8z9lls0s6ehupvordjdcor30geppm12kbvyropj1zs5#bounce.linkedin.com
...which obviously doesn't work for display in a 'from' field on the front-end. Email clients like Apple Mail and Gmail show mail-noreply#gmail.com or member#linkedin.com, so that's what I was going for too.
Anyways, after some more research, I discovered that the 'from' field in a Zend Mail Message object always looks something like this:
"user account name" <user#email.com>
The part in < > is what I was after, but simply doing $from = $zend_message->from only gave me the user's account name (hence my original question). After some more playing around, this is how I finally got it working:
$from = $zendMessage->from;
$start = strpos($from, '<');
$email = substr($from, $start, -1);
$result = str_replace('<', '', $email);
Hopefully this will save someone some frustration. If anyone knows of a simpler way of doing this, please let me know.
This works well..
$senderMailAddress = null;
foreach ( $message->getHeader('from')->getAddressList() as $address ) {
if ( $senderMailAddress === null) {
$senderMailAddress = $address->getEmail();
}
}
The main problem here is that many email programs, relay agents and virus scanner along the way do funny stuff to an actually simple and well defined email standard.
Zend_Mail_Message extends to Zend_Mail_Part which has a method called getHeaders(). This will have all the data from an email stored in the head versus the body which is accessed with getContent() and the actual email message.
With this method you'll get an array of all the key/value pairs in the header and while developing you should be able to determine which header field you will actually want. Once you know that you can then get the actual field with getHeader('field_name') or with its actual name directly.
However, if you have to many different email senders you may want to stick with the complete header array though and evaluate multiple fields for the best result like if there's an "reply-to" address. Again there are many uncertainties because the standard isn't always obeyed.
I need to parse mbox or email files using php, that is i would pass a file .mbox or .eml that contains several emails and parse it into its constituents e.g from, to, bcc etc.
is there any library that does it, or any code on how to do this in php?
thansk
There is a PEAR class http://pear.php.net/package/Mail_Mbox for that.
Albeit it's not difficult to separate a .mbox file manually. The individual mails are simply separated by /^From\s/ (may never appear in the mail body) and a block of Headers:. And most mail applications also store a length field in there. But it's indeed easier to use a readymade script for handling all the variations.
The PEAR class above works for getting individual messages out of MBOX, but if you want to then also parse the message into its constituent elements like "From Address", "Attachments", etc, then I would recommend mime_parser.php
In fact mime_parser.php can handle extracting the messages from a MBOX also, so depending on your needs, you might not need the PEAR class.
Here is the PEAR module Mail_Mbox for parsing mbox data:
https://pear.php.net/manual/en/package.mail.mail-mbox.php
if you need something faster for small needs, like extract all emails you collected into gmail by grouping into label and exported with google takeout in order to import the list let's say to mailchimp...
<?php
// tested with google mail > account > privacy > data exporter (with label)
// https://takeout.google.com/settings/takeout
$raw = file_get_contents('emails.mbox');
preg_match_all('/^Reply-To:\s(.*)$/im', $raw, $matches);
// avoid duplicate
$emails = array_unique($matches[1]);
$filtered_out = '';
// CSV field example (tested with mailchimp)
$filtered_in = 'Email Address' . "\n";
foreach ($emails as $email) {
$email = strtolower($email);
// filter out invalid emails, rarely
// happens that exporters makes mistakes ;)
// for example xxxxxxxxx#gmail.comx.xxxxxxxxxx.org
if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
$filtered_in .= $email . "\n";
} else {
$filtered_out .= $email . "\n";
}
}
header('Content-Type: text/plain');
// save to file
// file_put_contents('emails.csv', $filtered_in);
echo $filtered_in;
?>
hope this help!
I am sending email to some users and wants to know who had read it, means if some one had read that email then a log file will maintain which contain the email address of that user with date/time/IP.
For this I send a javascript function with the email (html template) which just alert the email address of the user when ever a user opens that email like:
for($n=0; $n<sizeof($checkBox); $n++){
$mail = new PHPMailer();
$mail->IsHTML(true);
$mail->Subject = $subject;
$function = "<script language='javascript'>function stats(emailId){alert(emailId);}</script>";
$bodyOpen = "<body onload='stats(".$checkBox[$n].");'>";
$msg_body .= $body .= "<table><tr><td>Hello Everyone</td></tr></table></body>";
$mail->Body = $function.$bodyOpen.$msg_body;
$mail->WordWrap = 50;
$mail->FromName = 'Muhammad Sajid';
$mail->IsMAIL();
$mail->From = 'webspot49#gmail.com';
$mail->AddAddress($checkBox[$n]);
$sent = $mail->Send();
}
the html template works fine and shows an alert popup on page load but it does not works if I use to send this html template.
And I only want to solve this issue using PHP5.x.x / javascript, no other software or third party tool.
Any help..?
Add Header to email:
Disposition-Notification-To: you#yourdomain.com
As mentioned above it's not reliable and it's better to do something like this:
<img src="http://yourdomain.com/emailreceipt.php?receipt=<email of receiver>" />
And log it in a database, although again this is restricted by the email client's ability to show images and sometimes it may even put the mail into junk because it doesn't detect an image... a workaround that would be to actually outputting an image (say your logo) at the end of that script.
Edit:
A quick lookup at the phpmailer class gave me the following:
$mail->ConfirmReadingTo = 'yourown#emailaddress.com';
but it's the same as the Disposition-Notification-To method above.
Send a beacon image in the emails like so
<img src='http://www.yourserver.com/beacon.php?email_id=$email_id&email_address=$user_address' style='width:1px;height:1px'>
And then use the beacon.php file to log the data. You will then want to output a 1X1 image with appropriate headers.
Important note Many popular email clients (such as Gmail) now block external images, so this is by far, not fool proof.
This is next to impossible to do 100% effectively.
You could control where the content is stored e.g. http://www.example.com/34hg038g85gb8no84g5 and provide a link in the email to that content, you can then detect when that URL was viewed.
Use a method used by MailChimp and other newsletter campaigns, put an invisible image in your email, this image should reside on a server you control, you can then detect when that image is hit when the user opens the email.
It is not possible by definition.
Mailreaders are not browsers, they don't support javascript. They don't even support proper CSS so dont expect too much. So I honestly don't see any way you can do what you're trying to do
I just add a single line:
$dt = date('F \ jS\,\ Y h:i:s a');
for($n=0; $n<sizeof($checkBox); $n++){
$mail = new PHPMailer();
$mail->IsHTML(true);
$mail->Subject = $subject;
$src = "<img src='msajid.isgreat.org/readmail.php?dt=".$dt."&eid=".$checkBox[$n]."' />";
$msg_body .= $src .= "<table><tr><td>Hello Everyone</td></tr></table>";
$mail->Body = $function.$bodyOpen.$msg_body;
$mail->WordWrap = 50;
$mail->FromName = 'Muhammad Sajid';
$mail->IsMAIL();
$mail->From = 'webspot49#gmail.com';
$mail->AddAddress($checkBox[$n]);
$sent = $mail->Send();
}
and in readmail.php file simply insert date/time and userid with a check (if not exist with attached date/time) & fixed it only for Gmail, hotmail but not for Yahoo...
Can some one help to also fix for Yahoo....?
Haaaa.
silly mistake just use complete url like:
$src = "<img src='http://www.msajid.isgreat.org/readmail.php?dt=".$dt."&eid=".$checkBox[$n]."' />";
and it will also work for Yahoo....
While I didn't discover exactly why the simple PHP file wasn't generating the included image (as mentioned in my post 6 hours ago), here is another very complicated way of generating an image file that wasn't rejected by my own PHP 5.4.30 web server.
Here is the code that I put into an index.php file within an /email_image/ subdirectory:
<?php
$message_id = $_REQUEST['message_id'];
$graphic_http = 'http://mywebsite.com/email_image/message_open_tracking.gif';
$filesize = filesize( 'message_open_tracking.gif' );
header( 'Pragma: public' );
header( 'Expires: 0' );
header( 'Cache-Control: must-revalidate, post-check=0, pre-check=0' );
header( 'Cache-Control: private',false );
header( 'Content-Disposition: attachment; filename="a_unique_image_name_' . $message_id . '.gif"' );
header( 'Content-Transfer-Encoding: binary' );
header( 'Content-Length: '.$filesize );
readfile( $graphic_http );
exit;
?>
For the image filename, I used the following:
http://mywebsite.com/email_image/?message_id=12345
Within the email_image folder is also a blank 1x1 gif image named "message_open_tracking.gif".
The index.php file can also be revised to make use of the message_id in order to mark that message as having been read. If other variables are included within the querystring, such as the recipient's email address, those values can also be used within that index.php file.
Many thanks to Bennett Stone for the following article:
http://www.phpdevtips.com/2013/06/email-open-tracking-with-php-and-mysql/
I know this is an old thread but I just had to respond... for those of us who must consider this, I suggest we put ourselves in the place of the people who have to write the anti-spam software to thwart our efforts. Detecting a ? or a .php (or other script/binary extension) inside an image tag would be trivial for me as a postulated 'spam assassin' programmer... just as identifying a 1x1 image would be...
I spent 2.5 yrs as National Digital Director for a presidential campaign that raised $20 million before we even had a candidate -- here's what I had developed for that campaign:
At send time (or before), generate a hash on the TO: email address and store that in the db next to the email address.
Use the hash we just generated to modify a small, but plainly visible logo in the email and make a copy of the logo with the hash in the logo file name eg: emxlogox.0FAE7E6.png - refer to that unique image in the email for the logo - make a copy of the logo with the hash name in the filename. This particular logo series only ever appears in targeted mass emails. Warn crew members not to copy it for other purposes (or to rename it extensively if they do). The first part of the filename needs to be something that will not appear in the logs in other contexts to speed your parsing and the code you have to craft to sort out false hits.
Parse the logs for occurrences of the logo being requested, and extract the hash from the filename to match back against the one email address. And your parsing program can also get the IP address and the time delta it took for them to get and open the email so you can identify highly responsive recipients and the ones who took a week to open the email. Do a geo-lookup on the IP and see if you get a match with the location you already have, and/or start recording their travel patterns (or proxy use patterns). Geo deltas could also be identifying email forwards.
Same hash, of course, is used to record clicks, and also the first and second opt-ins. (Now you have a 'dossier' of multiple opt-ins for responses to those abuse reports and you're protecting your email reputation, too).
This method can also be used to identify who forwards emails to their friends and you ask those 'good forwarders' to join some kind of elite digital volunteer crew, offer them discounts or rewards or whatever is appropriate for your business/project... in essence, that same hash also becomes a referrer code.
You can also ask them to right click on the logo in the email and save it without changing the filename, then post it to 'wherever' (the image should have a memorable, readable, meaningful shortlink on it, not an unreadable bit.ly shortlink). You can then use the Google Search API to identify who helped you out in that fashion and thank them or give them rewards... For this purpose, it helps if the first part of your logo filename is really unique like unsportingly.unique.emxlogox.0FAE7E6.png so you don't have to do millions of Google Search API queries - just search on the unique first part of the filename - and look at the hashes after you get the hits.
You store the links where their copy of the logo appeared in your db to add to your dossier of where on the net they are active and have helped you.
Yes, it's slow and burdensome, but in these days when we say we want to develop a 'relationship' with our email list, it's what you have to do to give individual treatment; identify and reward your friends. And yes, you end up with millions of those hashed filename images in one directory, but storage is cheap and it's worth it to really have that relationship with your peeps.
You can't add javascript to your emails.
The only solution would be to have only a link in the email, and the message on the server, Then you'd able to know that the message itself has been viewed.
Embedding a user specific image (1px blank might be good) in the email and record whether it is hot or not is a fair solution. But the problem Gmail like client block external images by default.
Please refer RFC-3798 for more details about MDN.
As the last post was awhile back, I am uncertain as to whether this method still works.
I tested this method on a server running PHP 5.4.30, and it does not seem to output an image.
This is some very simple code:
<img src="http://theservername.com/myaccount_email_read_offline.php">
Note that I removed the querystring and any additional code from this image.
Opening up that separate page, myaccount_email_read_offline.php did display the image.
However, trying to include the image by including a PHP file in its place did not work.
As some of the other answers have mentioned, it is possible to detect when a recipient has opened a message, if the message contains a remotely hosted image (and the recipient's mail client is set to open remotely hosted images).
UltraSMTP is an outgoing SMTP mail server that inserts a remotely hosted image in each outgoing message sent through the server, for this purpose.
See https://www.ultrasmtp.com/kb/developers.php for sample code for sending mail through UltraSMTP from a PHP script (using PHPMailer).