Im using the php mail function to send a link with many many paramaters. The url after being encoded can be 650 or more characters long because its holding variables to repopulate a form.
When I click on the link in my email its broken because a space has been inserted somewhere in the URL.
Heres my sendMail function:
protected function sendEmail($to, $subject, $body) {
$headers = 'MIME-Version: 1.0' . "\r\n";
$headers .= 'Content-type: text/html; charset=iso-8859-1' . '\r\n';
$headers .= 'From: Sales Order From <sales#imninjas.com>' . '\r\n';
$headers .= 'X-Mailer: PHP/' . phpversion() . '\r\n';
$body = '<html><body style="font-size: 10pt; font-family: Arial, Helvetica, sans-serif;">'.$body.'</body></html>';
return mail($to, $subject, $body, $headers);
}
Heres the code I call sendMail with. Its the '$salesUrl = $this->getSalesFormUrl();' that is the 650+ character url chock full of encoded paramaters.
function emailRep() {
$params = $this->getParamaterArray();
$shortUrl = $this->getShortUrl();
$salesUrl = $this->getSalesFormUrl();
$mailSubject = "Return to the sales order form for ".$params['clientName']." at ".$params['company'].".";
$mailBody = "The following information is from an order created on, ".date("l, F j, Y \a\t g:i a").",<br/><br/>";
$mailBody .= "Customer Contact Information:<br/>";
$mailBody .= "Name: ".$params['clientName'] params['company']."<br/>";
$mailBody .= "Shortened Url to Send to the Customer:<br/>";
$mailBody .= ($shortUrl) ? "<a href='".$shortUrl."'>".$shortUrl."</a><br/><br/>" : "There was an error shortening your url.<br/><br/>";
$mailBody .= "The URL back to the sales form: For sales rep use only, <strong>Do not give to the customer</strong>.:<br/>";
$mailBody .= "<span style='font-style: italic;'>Some email clients add special characters to long urls. If the link does not work then copy and paste it into your browser.</span><br/>";
$mailBody .= "<a href='".$salesUrl."'>".$salesUrl."</a><br/><br/>";
return ($this->sendEmail($params['repEmail'], $mailSubject, $mailBody));
}
And here's the URL I receive in my email, you'll notice the space '...BhsNKq Jsd_x4...' in the middle of the URL. This happens in a different place each time even if I'm sending the exact same url. To prove this I hard coded this url without a space in the emailRep method and sent it multiple times. The space moved around.
http://example.com/admin/index.php?fdJdj9QgFAbgXzPcNJ3AAdbxgotxdk28cNRMjPESW9yihVbKxHR_vaeU7TSZxqSfHDhPX9Jg-lPneu1H9cFHE7yJxUcdfpto_XNxtv6XHkgw_Vk7oy7aFRdnYzONPDltWxV01Zi23glqnU-z91XnpvrnpvNGSXYo4Q0t6UEKUmUp9Sh28JC7Va01Pmaibcc83M8dpCzzKYn5H_rX_BhsNKq Jsd_x4w7e4zHqputSWdc1Uwzezt2LS5xGQJHKxlF98qbzUZMhauxw_k5ebK8YPwDFr776GEb11WPzGtfhjIFE68zL9H2l3FOCFXea5qkHUmO9pCihThlegDLAHamuIeCmTiXSGv8cm_TorL-6q8NnYuvp6nEfpntthgrvx3enkhWP-FJ0P4vYYAvyJ45pbR9slaw9pbPLsnu4d9nNZSuXJZdll2WXJRc2XKYgu0zRvcwuqBSVwuzylQu4ILugxOJCciG7kF1Qx8vjZl5Y8sIqL59dRu9dfnP5yuXJ5dnl2eXJ3crLl7x8lVeoFJWKe1co_uoK_B1eXZFckV2RXaG-fHvazCuWvGKVV84u23DlzZUrVyZXZldmVyZ3K69c8so57z8
Here is the code I use to encode / decode the url paramaters before sending it through the email.
class UrlEncoder {
function compressUrl($url) {
return rtrim(strtr(base64_encode(gzdeflate($url, 9)), '+/', '-_'), '=');
}
function uncompressUrl($url) {
$startParams = strrpos($url, "?");
if($startParams) {
$paramaterString = substr($url, $startParams);
$host = substr($url, 0, strrpos($url, "?"));
$uncompressedParamaters = gzinflate(base64_decode(strtr($paramaterString, '-_', '+/')));
return $host."?".$uncompressedParamaters;
} else {
return NULL;
}
}
}
How do I prevent this space? I know I could shorten the URL with something like bit.ly however its an internal tool. I feel like there must be a way to stop the space from being inserted.
Who in their right mind uses a 650-character long query string?
My recommendation is to save the query-string server-side. Put it in a database with an AUTO_INCREMENT field, then you can get an ID for it. Then you can just send the URL as http://example.com/?email_key=ID_GOES_HERE, a much shorter URL. Then just look up the query string from the database.
Done.
I have what you need, http://www.9lessons.info/2009/01/split-url-from-sentence-using-php.html. Create tinyurl links using API,nothing in the database :)
Ok,I had same issue. My solution was my own link shrinking... Make new table in database with few rows, few lines of code in your old script, and new page for redirect... This is shortest explanation, if you need some help,just ask :)
EDIT:
function emailRep() {
$params = $this->getParamaterArray();
$shortUrl = $this->getShortUrl();
$salesUrl = $this->getSalesFormUrl();
/***********************************************************************************/
$arr = str_split('QWERTYUIOPLKJHGFDSAZXCVBNM123456789qwertyuioplkjhgfdsazxcvbnm'); // get all the characters into an array
shuffle($arr); // randomize the array
$arr = array_slice($arr, 0, 6); // get the first six (random) characters out
$short = implode('', $arr); // smush them back into a string
mysql_query("INSERT INTO shortlinks VALUES(NULL, '$salesUrl', '$short')");
/*******************************************************************************************/
$mailSubject = "Return to the sales order form for ".$params['clientName']." at ".$params['company'].".";
$mailBody = "The following information is from an order created on, ".date("l, F j, Y \a\t g:i a").",<br/><br/>";
$mailBody .= "Customer Contact Information:<br/>";
$mailBody .= "Name: ".$params['clientName'] params['company']."<br/>";
$mailBody .= "Shortened Url to Send to the Customer:<br/>";
$mailBody .= ($shortUrl) ? "<a href='".$shortUrl."'>".$shortUrl."</a><br/><br/>" : "There was an error shortening your url.<br/><br/>";
$mailBody .= "The URL back to the sales form: For sales rep use only, <strong>Do not give to the customer</strong>.:<br/>";
$mailBody .= "<span style='font-style: italic;'>Some email clients add special characters to long urls. If the link does not work then copy and paste it into your browser.</span><br/>";
$mailBody .= "<a href='".$short."'>".$short."</a><br/><br/>"; // Rename $salesUrl to $short
return ($this->sendEmail($params['repEmail'], $mailSubject, $mailBody));
}
And redirect page:
$token=$_GET['token']; // like http://example.com/out.php?token=ahgByT or make it cleaner with htaccess
$qry=mysql_query("SELECT * FROM links WHERE short='$token'");
$arr=mysql_fetch_array($qry);
$out=$arr['long_link'];
header("Location: ".$out);
?>
Related
I have a website that uses php mailer to send form input to a phone using the Verizon service. The issue is that the online form is being sent to a phone via text using the PHP mailer.
On the Android phones, the email is received properly and displayed in its entirety as a text message.
On an iPhone, the email is received as a text message, but it's truncated and only a portion is displayed. Notice that it stops at 'Cu.' It supposed to have about eight more lines of information pertaining to the appointment schedule. I'm wondering if iPhone has a character limit shorter than Android phones.
Anyone know how to avoid the text from being truncated on the iPhone?
I've googled for information, but all I get is how to fix the native iPhone email client. Which, isn't the issue.
Thank you.
It's pretty straight forward. The code pulls the form variables and assigns them as variable variables to the $message variable in a foreach loop.
<pre>
if ($OK_customers && $OK_appointments && $OK_customers_appointment) {
$message = '';
$selected_appt_day = date('l', strtotime($appt_date));
$selected_appt_date = date('m-d-Y', strtotime($appt_date));
$message .= "\r\n: ".$selected_appt_day.", ".$selected_appt_date."\r\n\r\n";
$message .= "Please confirm:\r\n\r\n";
foreach ($expected as $item) {
if (isset(${$item}) && !empty(${$item})) {
$val = ${$item};
}else {
$val = 'Not Selected';
}
if (is_array($val)) {
$val = implode(', ', $val);
}
$item = str_replace(['_', '-'], ' ', $item);
$message .= ucfirst($item) . ": $val\r\n";
}
$message = wordwrap($message, 70);
$mailSent = mail($to, $subject, $message, $headers);
if (!$mailSent) {
$errors['mailfail'] = true;
}
}
</pre>
I am trying to migrate our site to a new host that uses PHP5. Previously we were on PHP4.
I have a form that is not submitting and redirecting to the thankyou page after a user fills out a survey which worked previously on php4. I'm sure it's probably something obvious that I'm missing but I can't see why it doesn't work.
When I click submit, the survey page reloads, the URL gets ?submit=t added to the end and the email is not sent to me.
The code from our survey.php is shown below with my email address and most of the HTML form feilds removed. Can somebody point me in the right direction?
Thanks!
<?
$APP_ROOT = "../";
$FILE = __FILE__;
$TITLE="Service Survey";
if(!isset($submit)) {
include($APP_ROOT."include/header.php");
include($APP_ROOT."include/nava.php");
?>
<div class="bodymargin">
<img src="<?=$WEB_ROOT;?>images/titles/<?=$SECTION."_".$FILE;?>.gif" width="400" height="36"><br>
<br>
<form method="POST" action="<?=$FILE;?>.php?submit=t">
<?
if(isset($error)) {
while(list($key, $value) = each($HTTP_GET_VARS)) {
$$key = stripslashes($value);
}
print("<p class=\"alert\">". urldecode($error) . "</p>\n");
}
?>
<input type="text" name="name" value="<?=$name;?>">
</form>
<?
include($APP_ROOT."include/navb.php");
include($APP_ROOT."include/footer.php");
} else {
include_once($APP_ROOT . "functions/index.php");
include_once($APP_ROOT . "functions/form_validation.php");
$CONTINUE = TRUE;
$valid = new Validation($HTTP_POST_VARS);
if($CONTINUE = $valid->success) {
$to = "myemailaddress";
$subject = "Service Survey";
$from_email = $to;
$from_name = "mysite.com";
$headers = "From: $from_name<$from_email>\n";
$headers .= "Reply-To: <$email>\n";
$headers .= "Return-Path: <$from_email>\n";
$body = "The following information was just posted \n";
unset($HTTP_POST_VARS['required_fields']);
reset($HTTP_POST_VARS);
while(list($key, $value) = each($HTTP_POST_VARS)) {
if(!empty($value)) {
$body .= proper_form($key) . ": " . stripslashes($value) ."\n";
}
}
$body .= "\nThis is an automated message, please do not respond.";
mail($to,$subject,$body,$headers);
$URL = $WEB_ROOT . "/customer/thanks.php?form=" . $FILE;
server_redirector($URL);
} else {
while(list($key, $value) = each($HTTP_POST_VARS)) {
$rebound .= "&$key=" . urlencode(stripslashes($value));
}
$URL = $WEB_ROOT . "customer/survey.php?error=". urlencode(nl2br($valid->errors)) . $rebound;
server_redirector($URL);
die();
}
}
?>
regsiter_globals is not active in newer PHP versions.
So instead of using if(!isset($submit)) you have to use if(!isset($_GET['submit'])). And for posted values, you use $_POST['parameter'].
The __FILE__ constant is possibly not returning what you expect, or not what it previously did. from the docs
Since PHP 4.0.2, __ FILE__ always contains an absolute path with symlinks resolved whereas in older versions it contained relative path under some circumstances.
So you may be getting an absolute path now, instead of a relative one.
Also check if your new installation allows for short_open_tags as explained in the docs
$HTTP_POST_VARS is deprecated. You will want to replace it with $_POST.
Alternatively, you can just add $HTTP_POST_VARS = $_POST; at the beginning of the script to avoid editing every line (Not really recommended).
I have a mysql database table called "leads" with an id column, a name column, and an email column. I currently have users selecting a lead from a multiple select box, which is returned as an array from an html form with $_POST method. I have the value for the select box items as the email column, and what is shown to the user on the front end is the name column. However, I want to be able to return two values, the email and the name, for later use. I need to have the email value(s) able to be imploded with commas between them, so I can later send them emails using PHP's mail function. However, when a user looks at sent emails, I want to show them the name value(s). I have read that I can either parse the array, or use the id column set as the value, which seems more practical, however, I am not sure how I would go about this. Any ideas? Thanks in advance for any help!
*UPDATE*
Basically, the users that log into the site have their own leads in a mysql database. I need them to be able to go to a 'send email' page, where they can select a lead, or multiple leads, by name. Then there is a subject field, and a message field so they can write the email, and then I have a 'send email' form submit button. After they click 'send email' I want to get back the email addresses and names of the leads they selected, for later use. I need to have the email addresses separated by commas, so that I can send them through a php mail function... But the important thing is, I want the info from the form to be stored in a database table called 'PendingEmails', and I am going to run a cron job to run a script that finds what emails need to be sent, and sends them... After an email is sent, I need to put the names, subject, and message from the email in a separate database, called 'SentEmails'. On a different page on the site, I want the users to be able to see all the emails they sent, but I want them to see the names of who they sent it to, rather than the email addresses. This is why I need both the names and the emails. I need emails for the mail function, and names to be displayed back to the user. I like your idea of using the id and running the rest server side, I just dont know how I would do this. Hope this helped.
Here is the select box:
<select data-placeholder="Select Lead(s) To Email..." multiple="true" class="chzn-container-multi" name="selectleads[]"style="width:505px;">
<?php
do {
?>
<option value="<?php echo $row_rsAllLeads['Email']?>"><?php echo $row_rsAllLeads['FullName']?></option>
<?php
} while ($row_rsAllLeads = mysql_fetch_assoc($rsAllLeads));
$rows = mysql_num_rows($rsAllLeads);
if($rows > 0) {
mysql_data_seek($rsAllLeads, 0);
$row_rsAllLeads = mysql_fetch_assoc($rsAllLeads);
}
?>
</select>
And here is the actual form action:
$editFormAction = $_SERVER['PHP_SELF'];
if (isset($_SERVER['QUERY_STRING'])) {
$editFormAction .= "?" . htmlentities($_SERVER['QUERY_STRING']);
}
if ((isset($_POST["MM_insert"])) && ($_POST["MM_insert"] == "form")) {
$startcode = $_POST['messagefield'];
$replaced = preg_replace( '/\\\\(?="|\')/', '', $startcode );
$selected = $_POST['selectleads'];
$collectedleads = implode(", ", $_POST['selectleads']);
$to = $collectedleads;
$subject = $_POST['subjectfield'];
$body = $replaced;
$headers = "MIME-Version: 1.0\r\n";
$headers .= "Content-type: text/html; charset=iso-8859-1\r\n";
$headers .= "From: " . $row_rs_CurrentUser['FirstName'] . " " . $row_rs_CurrentUser['LastName'] . " <" . $row_rs_CurrentUser['Email'] . ">";
if (mail($to, $subject, $body, $headers)) {
} else {
echo("<p>Message delivery failed...</p>");
}
}
The code you gave me and I tried (and failed) to edit and make work:
$editFormAction = $_SERVER['PHP_SELF'];
if (isset($_SERVER['QUERY_STRING'])) {
$editFormAction .= "?" . htmlentities($_SERVER['QUERY_STRING']);
}
if ((isset($_POST["MM_insert"])) && ($_POST["MM_insert"] == "form")) {
$startcode = $_POST['messagefield'];
$replaced = preg_replace( '/\\\\(?="|\')/', '', $startcode );
mysql_select_db($database_myBackOfficeConn, $myBackOfficeConn);
$collectedleads = implode(", ", $_POST['selectleads']);
//arrays to store email addresses and names
$emails = array();
$names = array();
foreach ($collectedleads as $id) {
mysql_query("SELECT Email, FullName FROM Leads
WHERE Id = " . mysql_real_escape_string($id));
while ($row = mysql_fetch_assoc()) {
$emails[] = $row['Email'];
$names[] = $row['FullName'];
}
}
$to = $collectedleads;
$subject = $_POST['subjectfield'];
$body = $replaced;
$headers = "MIME-Version: 1.0\r\n";
$headers .= "Content-type: text/html; charset=iso-8859-1\r\n";
$headers .= "From: " . $row_rs_CurrentUser['FirstName'] . " " . $row_rs_CurrentUser['LastName'] . " <" . $row_rs_CurrentUser['Email'] . ">";
if (mail($to, $subject, $body, $headers)) {
} else {
echo("<p>Message delivery failed...</p>");
}
}
?>
I think it would make more sense to do the retrieving of data on the server-side. Instead of the email addresses, set the <option> values to your database's id column values.
EDIT: Changed most of the answer after discussing with OP
Bearing in mind that the code you posted was just a snippet, and so I have no way of testing this, you could try something along these lines:
<select data-placeholder="Select Lead(s) To Email..." multiple="true"
class="chzn-container-multi" name="selectleads[]"style="width:505px;">
<?php
/* I think while is better, in case there are no results.
do...while would attempt to echo the first result in a set even
if there were no results, which would give an error, methinks. */
//Use the id field of your database when you populate the select
while ($row_rsAllLeads = mysql_fetch_assoc($rsAllLeads)) { ?>
<option value="<?php echo $row_rsAllLeads['id']?>">
<?php echo $row_rsAllLeads['FullName']?></option>
<?php
}
/* What is this block used for? */
$rows = mysql_num_rows($rsAllLeads);
if($rows > 0) {
mysql_data_seek($rsAllLeads, 0);
$row_rsAllLeads = mysql_fetch_assoc($rsAllLeads);
}
?>
</select>
I'm uncertain as to the purpose of the code block at the end so I just left it. I assume you do something else with that data...?
So now your <select> is exactly the same as before, but instead of actual email addresses it will hand back the corresponding database ids instead.
Now, on submitting the data, we change our tack slightly:
<?php
$editFormAction = $_SERVER['PHP_SELF'];
if (isset($_SERVER['QUERY_STRING'])) {
$editFormAction .= "?" . htmlentities($_SERVER['QUERY_STRING']);
}
if ((isset($_POST["MM_insert"])) && ($_POST["MM_insert"] == "form")) {
$startcode = $_POST['messagefield'];
$replaced = preg_replace( '/\\\\(?="|\')/', '', $startcode );
$selected = $_POST['selectleads'];
/* NEW CODE */
/*selectleads[] is now an array of your database's ids.
You can now run a query to get whatever information you
need. In this case, you want the email addresses, so:
*/
$collectedleads = $_POST['selectleads'];
$emailaddylist = array();
foreach ($collectedleads as $id) {
$x = mysql_query("SELECT `Email` FROM `leads` WHERE `id` = " .
mysql_real_escape_string($id));
$x_assoc = $x->fetch_assoc();
$emailaddylist[] = $x['Email'];
}
/*Now you have an array of email addresses that correspond to
the ids you were sent via $_POST.
*/
$emailaddystring = implode(", ", $emailaddylist);
$to = $emailaddystring;
/*If you want to use any other data from the database,
you still have an array of ids in $collectedleads.
Just run another query to get the data you want.*/
/* END OF NEW CODE */
$subject = $_POST['subjectfield'];
$body = $replaced;
$headers = "MIME-Version: 1.0\r\n";
$headers .= "Content-type: text/html; charset=iso-8859-1\r\n";
$headers .= "From: " . $row_rs_CurrentUser['FirstName'] . " " . $row_rs_CurrentUser['LastName'] . " <" . $row_rs_CurrentUser['Email'] . ">";
if (mail($to, $subject, $body, $headers)) {
} else {
echo("<p>Message delivery failed...</p>");
}
}
?>
Because we are handed the ids in an array, we can use them to get whatever information we want from the database. In this case we're just getting the email addresses. If you want to retrieve any other information, you can use the same technique - the list of ids still exists in $collectedleads, so you can run another query to get whatever data you need.
After an email is sent, I need to put the names, subject, and message
from the email in a separate database, called 'SentEmails'
In that case, use the id data in $collectedleads to run a SELECT query on leads to get the information you need (name, email address, whatever), and run an INSERT query on the SentEmails table to copy that information.
Hope this helps.
CAVEAT:
The use of mysql is discouraged in favour of mysqli. To quote the page:
If you are using MySQL versions 4.1.3 or later it is strongly
recommended that you use the mysqli extension instead.
It works almost exactly the same; in most cases all you need to do is to put the i in front of it. Some functions don't work with it, or have better alternatives. You should check it out.
What I would do, I would add a hidden field named something along the lines of "lead_name" and fill it with jQuery or just plain JS on an onblur event with the value of the selected lead.
$("#lead_name").val($("#lead option:selected").text());
I've never done that before and simply need a little advice how to do so …
I have a index.php file with a simple contact form.
<form id="contactform" method="post" action="<?php echo $_SERVER["SCRIPT_NAME"] ?>">
The index.php file has the following script on top.
<!DOCTYPE html>
<html dir="ltr" lang="en-US">
<?php
//Vars
$Name = Trim(stripslashes($_POST['author']));
$EmailFrom = Trim(stripslashes($_POST['email']));
$Subject = Trim(stripslashes($_POST['subject']));
$Type = Trim(stripslashes($_POST['type']));
$Comment = Trim(stripslashes($_POST['message']));
$EmailTo = "address#something.com";
//Validation
$valid = true;
if ( $Name == "" ) $valid = false;
if ( isValidEmail( $EmailFrom ) == 0 ) $valid = false;
if ($Subject == "") $valid = false;
if ($Comment == "") $valid = false;
function isValidEmail( $email = null ) {
return preg_match( "/^[\d\w\/+!=#|$?%{^&}*`'~-][\d\w\/\.+!=#|$?%{^&}*`'~-]*#[A-Z0-9][A-Z0-9.-]{1,61}[A-Z0-9]\.[A-Z]{2,6}$/ix", $email );
}
//Body
$Body = $Type;
$Body .= "\n\n";
$Body .= $Comment;
//Headers
$email_header = "From: " . $EmailFrom . "\r\n";
$email_header .= "Content-Type: text/plain; charset=UTF-8\r\n";
$email_header .= "Reply-To: " . $EmailFrom . " \r\n";
//Send
if ($valid)
$success = mail($EmailTo, $Subject, $Body, $email_header);
?>
I have two questions now:
1.)
How exactly can I render/not-render certain stuff when either the validation went wrong or a success or an error comes back when submitting the mail?
e.g. I know that I can do that!
if ( !$valid )
print "Failed to make contact. Enter valid login credentials! <a href='/#contact' title='try again'>try again?</a>";
if ( $success )
print "Successfully made contact.";
else
print "Failed to make contact. <a href='/#contact' title='try again'>try again?</a>"; */
?>
However $valid will always be wrong on page-load when not submitting the form and also the email will always return the error message on the first page load. How can I only render or not render specific stuff when the form is submitted?
E.g. When submitting the form and a success comes back I don't want to render the #contactform anymore. I simply want to print "Successfully made contact" into an h1 or so.
How can I make that happen? It's probably rather simple I just can't find a solution for myself.
2.)
When using $_SERVER["SCRIPT_NAME"] or PHP_SELF as action the url after submitting the form will always change to "mydomain.com/index.php". Can I prevent that from happening? I want to submit the index.php file itself however I just don't like it when /index.php is written into the url. Is it possible to stop that from happening?
Thank you for your help!
Matt,
For the first question as to printing to the screen based on success or failure of the email, your checks seem fine, but you probably aren't going to get an email failure in time to display that to the screen. That said, you just need to wrap your second set of code in an if statement. Something like this:
if( isset($_POST['Submit']) ){ //only attempt to display if form submitted.
//Your code here
}
As for not including the directory in the form action, there are many ways to do this, but here's one:
$scriptString= explode('/',$_SERVER['SCRIPT_NAME']);
$scriptSize = count($scriptString)-1;
$script = $scriptString[$scriptSize];
And then use $script in the form action.
Problem: Blank email from PHP web application.
Confirmed: App works in Linux, has various problems in Windows server environment. Blank emails are the last remaining problem.
PHP Version 5.2.6 on the server
I'm a librarian implementing a PHP based web application to help students complete their assignments.I have installed this application before on a Linux based free web host and had no problems.
Email is controlled by two files, email_functions.php and email.php. While email can be sent, all that is sent is a blank email.
My IT department is an ASP only shop, so I can get little to no help there. I also cannot install additional libraries like PHPmail or Swiftmailer.
You can see a functional copy at http://rpc.elm4you.org/ You can also download a copy from Sourceforge from the link there.
Thanks in advance for any insight into this!
email_functions.php
<?php
/**********************************************************
Function: build_multipart_headers
***********************************************************
Purpose:
Creates email headers for a message of type multipart/mime
This will include a plain text part and HTML.
**********************************************************/
function build_multipart_headers($boundary_rand)
{
global $EMAIL_FROM_DISPLAY_NAME, $EMAIL_FROM_ADDRESS, $CALC_PATH, $CALC_TITLE, $SERVER_NAME;
// Using \n instead of \r\n because qmail doubles up the \r and screws everything up!
$crlf = "\n";
$message_date = date("r");
// Construct headers for multipart/mixed MIME email. It will have a plain text and HTML part
$headers = "X-Calc-Name: $CALC_TITLE" . $crlf;
$headers .= "X-Calc-Url: http://{$SERVER_NAME}/{$CALC_PATH}" . $crlf;
$headers .= "MIME-Version: 1.0" . $crlf;
$headers .= "Content-type: multipart/alternative;" . $crlf;
$headers .= " boundary=__$boundary_rand" . $crlf;
$headers .= "From: $EMAIL_FROM_DISPLAY_NAME <$EMAIL_FROM_ADDRESS>" . $crlf;
$headers .= "Sender: $EMAIL_FROM_DISPLAY_NAME <$EMAIL_FROM_ADDRESS>" . $crlf;
$headers .= "Reply-to: $EMAIL_FROM_DISPLAY_NAME <$EMAIL_FROM_ADDRESS>" . $crlf;
$headers .= "Return-Path: $EMAIL_FROM_DISPLAY_NAME <$EMAIL_FROM_ADDRESS>" . $crlf;
$headers .= "Date: $message_date" . $crlf;
$headers .= "Message-Id: $boundary_rand#$SERVER_NAME" . $crlf;
return $headers;
}
/**********************************************************
Function: build_multipart_body
***********************************************************
Purpose:
Builds the email body content to go with the headers from
build_multipart_headers()
**********************************************************/
function build_multipart_body($plain_text_message, $html_message, $boundary_rand)
{
//$crlf = "\r\n";
$crlf = "\n";
$boundary = "__" . $boundary_rand;
// Begin constructing the MIME multipart message
$multipart_message = "This is a multipart message in MIME format." . $crlf . $crlf;
$multipart_message .= "--{$boundary}{$crlf}Content-type: text/plain; charset=\"us-ascii\"{$crlf}Content-Transfer-Encoding: 7bit{$crlf}{$crlf}";
$multipart_message .= $plain_text_message . $crlf . $crlf;
$multipart_message .= "--{$boundary}{$crlf}Content-type: text/html; charset=\"iso-8859-1\"{$crlf}Content-Transfer-Encoding: 7bit{$crlf}{$crlf}";
$multipart_message .= $html_message . $crlf . $crlf;
$multipart_message .= "--{$boundary}--$crlf$crlf";
return $multipart_message;
}
/**********************************************************
Function: build_step_email_body_text
***********************************************************
Purpose:
Returns a plain text version of the email body to be used
for individually sent step reminders
**********************************************************/
function build_step_email_body_text($stepnum, $arr_instructions, $dates, $query_string, $teacher_info ,$name, $class, $project_id)
{
global $CALC_PATH, $CALC_TITLE, $SERVER_NAME;
$step_email_body =<<<BODY
$CALC_TITLE
Step $stepnum: {$arr_instructions["step$stepnum"]["title"]}
Name: $name
Class: $class
BODY;
$step_email_body .= build_text_single_step($stepnum, $arr_instructions, $dates, $query_string, $teacher_info);
$step_email_body .= "\n\n";
$step_email_body .=<<<FOOTER
The $CALC_TITLE offers suggestions, but be sure to check with your teacher to find out the best working schedule for your assignment!
If you would like to stop receiving further reminders for this project, click the link below:
http://$SERVER_NAME/$CALC_PATH/deleteproject.php?proj=$project_id
FOOTER;
// Wrap text to 78 chars per line
// Convert any remaining HTML <br /> to \r\n
// Strip out any remaining HTML tags.
$step_email_body = strip_tags(linebreaks_html2text(wordwrap($step_email_body, 78, "\n")));
return $step_email_body;
}
/**********************************************************
Function: build_step_email_body_html
***********************************************************
Purpose:
Same as above, but with HTML
**********************************************************/
function build_step_email_body_html($stepnum, $arr_instructions, $dates, $query_string, $teacher_info, $name, $class, $project_id)
{
global $CALC_PATH, $CALC_TITLE, $SERVER_NAME;
$styles = build_html_styles();
$step_email_body =<<<BODY
<html>
<head>
<title> $CALC_TITLE </title>
$styles
</head>
<body>
<h1> $CALC_TITLE Schedule </h1>
<strong>Name:</strong> $name <br />
<strong>Class:</strong> $class <br />
BODY;
$step_email_body .= build_html_single_step($stepnum, $arr_instructions, $dates, $query_string, $teacher_info);
$step_email_body .=<<<FOOTER
<p>
The $CALC_TITLE offers suggestions, but be sure to check with your teacher to find out the best working schedule for your assignment!
</p>
<p>
If you would like to stop receiving further reminders for this project,
click this link.
</p>
</body>
</html>
FOOTER;
return $step_email_body;
}
/**********************************************************
Function: build_html_styles
***********************************************************
Purpose:
Just returns a string of <style /> for the HTML message body
**********************************************************/
function build_html_styles()
{
$styles =<<<STYLES
<style type="text/css">
body { font-family: Arial, sans-serif; font-size: 85%; }
h1 { font-size: 120%; }
table { border: none; }
tr { vertical-align: top; }
img { display: none; }
hr { border: 0; }
</style>
STYLES;
return $styles;
}
/**********************************************************
Function: linebreaks_html2text
***********************************************************
Purpose:
Convert <br /> html tags to \n line breaks
**********************************************************/
function linebreaks_html2text($in_string)
{
$out_string = "";
$arr_br = array("<br>", "<br />", "<br/>");
$out_string = str_replace($arr_br, "\n", $in_string);
return $out_string;
}
?>
email.php
<?php
require_once("include/config.php");
require_once("include/instructions.php");
require_once("dbase/dbfunctions.php");
require_once("include/email_functions.php");
ini_set("sendmail_from", "reference#cna-qatar.edu.qa");
ini_set("SMTP", "mail.qatar.net.qa");
// Verify that the email has not already been sent by checking for a cookie
// whose value is generated each time the form is loaded freshly.
if (!(isset($_COOKIE['rpc_transid']) && $_COOKIE['rpc_transid'] == $_POST['transid']))
{
// Setup some preliminary variables for email.
// The scanning of $_POST['email']already took place when this file was included...
$to = $_POST['email'];
$subject = $EMAIL_SUBJECT;
$boundary_rand = md5(rand());
$mail_type = "";
switch ($_POST['reminder-type'])
{
case "progressive":
$arr_dbase_dates = array();
$conn = rpc_connect();
if (!$conn)
{
$mail_success = FALSE;
$mail_status_message = "Could not register address!";
break;
}
// Sanitize all the data that will be inserted into table...
// We need to remove "CONTENT-TYPE:" from name/class to defang them.
// Additionall, we can't allow any line-breaks in those fields to avoid
// hacks to email headers.
$ins_name = mysql_real_escape_string($name);
$ins_name = eregi_replace("CONTENT-TYPE", "...Content_Type...", $ins_name);
$ins_name = str_replace("\n", "", $ins_name);
$ins_class = mysql_real_escape_string($class);
$ins_class = eregi_replace("CONTENT-TYPE", "...Content_Type...", $ins_class);
$ins_class = str_replace("\n", "", $ins_class);
$ins_email = mysql_real_escape_string($email);
$ins_teacher_info = $teacher_info ? "YES" : "NO";
switch ($format)
{
case "Slides": $ins_format = "SLIDES"; break;
case "Video": $ins_format = "VIDEO"; break;
case "Essay":
default: $ins_format = "ESSAY"; break;
}
// The transid from the previous form will be used as a project identifier
// Steps will be grouped by project identifier.
$ins_project_id = mysql_real_escape_string($_POST['transid'] . md5(rand()));
$arr_dbase_dates = dbase_dates($dates);
$arr_past_dates = array();
// Iterate over the dates array and build a SQL statement for each one.
$insert_success = TRUE;
//
$min_reminder_date = date("Ymd", mktime(0,0,0,date("m"),date("d")+$EMAIL_REMINDER_DAYS_AHEAD,date("Y")));
for ($date_index = 0; $date_index < sizeof($arr_dbase_dates); $date_index++)
{
// Make sure we're using the right keys...
$ins_date_index = $date_index + 1;
// The insert will only happen if the date of the event is in the future.
// For dates today and earlier, no insert.
// For dates today or after the reminder deadline, we'll send the email immediately after the inserts.
if ($arr_dbase_dates[$date_index] > (int)$min_reminder_date)
{
$qry =<<<QRY
INSERT INTO email_queue
(
NOTIFICATION_ID,
PROJECT_ID,
EMAIL,
NAME,
CLASS,
FORMAT,
TEACHER_INFO,
STEP,
MESSAGE_DATE
)
VALUES (
NULL,
'$ins_project_id',
'$ins_email',
'$ins_name',
'$ins_class',
'$ins_format',
'$ins_teacher_info',
$ins_date_index, /*step number*/
{$arr_dbase_dates[$date_index]} /* Date in the integer format yyyymmdd */
)
QRY;
// Attempt to do the insert...
$result = mysql_query($qry);
// If even one insert fails, bail out.
if (!$result)
{
$mail_success = FALSE;
$mail_status_message = "Could not register address!";
break;
}
}
// For dates today or earlier, store the steps=>dates in an array so the mails can
// be sent immediately.
else
{
$arr_past_dates[$ins_date_index] = $arr_dbase_dates[$date_index];
}
}
// Close the connection resources.
mysql_close($conn);
// SEND OUT THE EMAILS THAT HAVE TO GO IMMEDIATELY...
// This should only be step 1, but who knows...
//var_dump($arr_past_dates);
for ($stepnum=1; $stepnum<=sizeof($arr_past_dates); $stepnum++)
{
$email_teacher_info = ($teacher_info && $EMAIL_TEACHER_REMINDERS) ? TRUE : FALSE;
$boundary = md5(rand());
$plain_text_body = build_step_email_body_text($stepnum, $arr_instructions, $dates, $query_string, $email_teacher_info ,$name, $class, $ins_project_id);
$html_body = build_step_email_body_html($stepnum, $arr_instructions, $dates, $query_string, $email_teacher_info ,$name, $class, $ins_project_id);
$multipart_headers = build_multipart_headers($boundary);
$multipart_body = build_multipart_body($plain_text_body, $html_body, $boundary);
mail($to, $subject . ": Step " . $stepnum, $multipart_body, $multipart_headers, "-fresearch#rpc.elm4you.org");
}
// Set appropriate flags and messages
$mail_success = TRUE;
$mail_status_message = "Email address registered!";
$mail_type = "progressive";
set_mail_success_cookie();
break;
// Default to a single email message.
case "single":
default:
// We don't want to send images in the message, so strip them out of the existing structure.
// This big ugly regex strips the whole table cell containing the image out of the table.
// Must find a better solution...
//$email_table_html = eregi_replace("<td class=\"stepImageContainer\" width=\"161px\">[\s\r\n\t]*<img class=\"stepImage\" src=\"images/[_a-zA-Z0-9]*\.gif\" alt=\"Step [1-9]{1} logo\" />[\s\r\n\t]*</td>", "\n", $table_html);
// Show more descriptive text based on the value of $format
switch ($format)
{
case "Video": $format_display = "Video"; break;
case "Slides": $format_display = "Presentation with electronic slides"; break;
case "Essay":
default:
$format_display = "Essay"; break;
}
$days = (int)$days;
$html_message = "";
$styles = build_html_styles();
$html_message =<<<HTMLMESSAGE
<html>
<head>
<title> $CALC_TITLE </title>
$styles
</head>
<body>
<h1> $CALC_TITLE Schedule </h1>
<strong>Name:</strong> $name <br />
<strong>Class:</strong> $class <br />
<strong>Email:</strong> $email <br />
<strong>Assignment type:</strong> $format_display <br /><br />
<strong>Starting on:</strong> $date1 <br />
<strong>Assignment due:</strong> $date2 <br />
<strong>You have $days days to finish.</strong><br />
<hr />
$email_table_html
</body>
</html>
HTMLMESSAGE;
// Create the plain text version of the message...
$plain_text_message = strip_tags(linebreaks_html2text(build_text_all_steps($arr_instructions, $dates, $query_string, $teacher_info)));
// Add the title, since it doesn't get built in by build_text_all_steps...
$plain_text_message = $CALC_TITLE . " Schedule\n\n" . $plain_text_message;
$plain_text_message = wordwrap($plain_text_message, 78, "\n");
$multipart_headers = build_multipart_headers($boundary_rand);
$multipart_message = build_multipart_body($plain_text_message, $html_message, $boundary_rand);
$mail_success = FALSE;
if (mail($to, $subject, $multipart_message, $multipart_headers, "-reference#cna-qatar.edu.qa"))
{
$mail_success = TRUE;
$mail_status_message = "Email sent!";
$mail_type = "single";
set_mail_success_cookie();
}
else
{
$mail_success = FALSE;
$mail_status_message = "Could not send email!";
}
break;
}
}
function set_mail_success_cookie()
{
// Prevent the mail from being resent on page reload. Set a timestamp cookie.
// Expires in 24 hours.
setcookie("rpc_transid", $_POST['transid'], time() + 86400);
}
?>
Instead of sending it, build the email and display all of the vars used in the mail call to the screen and comment out the mail call. That will confirm that the vars are being properly constructed.
Then start using the mail function again, if you have access to mail logs that would help as well, as it may give you more information. Also, take a look at the headers on the email you receive as that also may show you that a header or 2 is messed up.
Also try setting $crlf = "\r\n";
brett, if you think it's the headers, i'd try the bare minimum and get it to work. once it works, start adding headers until you get the error. then let us know what the problem is.