Send Mail on a LAMP Droplet on DigitalOcean

Setting up a LAMP stack server on DigitalOcean: Super Easy.
Getting a website up and running: Super Easy.
Sending an email from that website: Holy Crap.

This may be all common sense to any of those Linux gurus out there. But since I do all of my development on a Windows box and my work environment uses Cold Fusion, I am a bit of a newbie.

This is what happened.

By going to /var/log/mail.log, I noticed the error constantly:

Oct 26 21:08:57 localhost sm-msp-queue[1269]: unable to qualify my own domain name (localhost) -- using short name
Oct 26 21:10:06 localhost sendmail[1398]: My unqualified host name (localhost) unknown; sleeping for retry

I also noticed on my PHP test page that it took forever to run a mail command. What the heck was going on?

After some Google troubleshooting, I found a way to test send mail by using this command

time echo test | sendmail myemail@gmail.com

This would return 3 values. One was always over a minute.

Interesting.

I then found some other snippets of help that said this error usually had to do with domain resolution. “But Internet, my hostfile looks right! Why do you say that it’s wrong?”

What was actually missing was a IPv4 entry for localhost and the name of the server. Opening up /etc/hosts and adding the following line fixes the issue.

#YOUR_HOST_NAME is actually the name of the server by using the command "hostname"
127.0.0.1 localhost.localdomain localhost YOUR_HOST_NAME

Restart sendmail by doing

sudo service sendmail restart

and you should be golden. Run the time test again, and it will be below 1 second.

 

Advertisement

Rename All Tables in MySQL

One of the products I support is the Kayako support suite.  While undergoing the upgrade from version 3 to version 4, I wanted to remove the prefix on each table.  Of course, I didn’t want to rename every table manually.  By doing some googling, I found some code that I tweaked to do my bidding.

SELECT CONCAT('RENAME TABLE `', TABLE_SCHEMA, '`.`', TABLE_NAME, '` TO `', TABLE_SCHEMA, '`.`prefix_', TABLE_NAME, '`;')
FROM `TABLES` WHERE `TABLE_SCHEMA` = "test_database_name";

First, as always do a backup.

Then, run this on the information_schema schema.  It will generate a list of all the tables with the rename table commands.  After it’s generated, copy the results into notepad, replace prefix_ with whatever you wish and re-run it on the information_schema schema.

Wallah!  You just renamed all your tables.

Amazon SQS (Queuing) Service and PHP

Queuing: something that just needs to happen if background processing needs to be done.  Well, Amazon’s AWS service has that feature and I had to set it up.  Here are some notes on what I did to set it up for a email queuing service.  The first few steps are probably repeats if you are already using the PHP SDK for other services.

1) Get the SDK- http://aws.amazon.com/sdkforphp
First things first, download the SDK from Amazon and put it in a PHP/Apache accessible directory.

2) Get your credentials – http://aws.amazon.com/articles/4261
Follow the directions on this site to get your secret key and access keys.
Next, copy the config-sample.inc.php that is located in the root of the SDK to the same directory with the new name config.inc.php. Use the key information to fill  out theconfig.inc.php and save the file.

3) Run the compatibility test
Go to your localhost at  http://${HTTP_HOST}/${AMAZON_SDK_DIRECTORY}/_compatibility_test/sdk_compatibility_test.php and make sure there’s a green bar at the bottom saying you’re good to go.

4) Watch the videos / Read through the documentation
Seriously, the videos were the best part of the documentation. Easy to follow, said a lot.  http://d1un85p0f2qstc.cloudfront.net/fundamentals_sqs/video.html

PHP Amazon Generic Documentation: http://aws.amazon.com/documentation/sdkforphp/

 

PHP SDK Documentation: http://docs.amazonwebservices.com/AWSSDKforPHP/latest/

5) We got some coding to do.
This should be fairly easy if you followed the videos and checked out the documentation.  I created the queue by hand in the administrator, so I did not need to go through that by code.  My goal was to make two functions: one to add a message to the queue, and one to retrieve and delete it.

First we need to include the SDK

include_once("sdk.class.php");

The addToQueue function is used to push a message onto the queue.  This would be called when the front end of the application needs to send an email or do some background processing.  It’s a very quick action and allows the end user to not have to wait for the entire action to take place before moving on to do something else.

function addToQueue($to, $emailTemplate) {
	//initiate the object
	$sqs = new AmazonSQS();
	$queue_url = "https://queue.amazonaws.com/SOME_NUMBER/QUEUE_NAME";

	//an example array of the message we could sent to the queue
	$arr = array('to' => $to, 'template' => $emailTemplate);
	//json encode the message so that we can easily send multiple variables in the same string
	//	php has json ecoding built in, so it's pretty light
	$message = json_encode($arr);
	//actually add the message to the queuing system
	$addEmailResponse = $sqs->send_message($queue_url, $message);
}

The processMessage function is used to do the actual work.  In reality, this would be called via a cron often and would churn through all of the messages.

function processMessage () {
	$sqs = new AmazonSQS();
	$queue_url = "https://queue.amazonaws.com/SOME_NUMBER/QUEUE_NAME";
	//get a "random" message from the amazon queue
	//	also visibility timeout tells amazon how long to keep the lock on that particular record
	//	this example is using 30 seconds, so that means that we have 30 seconds to send the email
	//	before it can be found again.  This can be changed
	$messageResponse = $sqs->receive_message($queue_url, array( 'VisibilityTimeout' => 30));
	//get the JSON encoded message that is brought with the message
	$message = json_decode($messageResponse->body->ReceiveMessageResult->Message->Body);
	//we need the receipt handle for deletion.  Amazon needs to know which message to delete
	$receiptHandle = $messageResponse->body->ReceiveMessageResult->Message->ReceiptHandle;
	//make sure we found an acutal message and the queue isn't empty
	$everythingHasGoneWell = isset($message);

	if($everythingHasGoneWell)
	{
		//actually send the email.  Email function should return a boolean if it's succesful or not
		$everythingHasGoneWell = sendEmail($message->to, $message->template);
		//if the email was actually sent go ahead, otherwise it will try again when the visibility timeout is met
		if ($everythingHasGoneWell) {
			//delete the message from the queuing system, really we should be checking for response codes throughout the
			//	system, here included.
			$deleteResponse = $sqs->delete_message($queue_url, $receiptHandle);
		}
	}
	else
	{
		//something went wrong or there were no emails in the queue
		print_r("No emails to process.");
	}
}

 

Make Gmail Look More Like Outlook

One complaint I always get around the office is “Gmail sucks.  It doesn’t look like Outlook.”   For a lot of businesses, this statement would not matter or occur. However, my company is all in on the Google Apps bandwagon and we are not going to go to an Exchange/Outlook ecosystem to satisfy a few people.

I really like how Gmail displays most information.  It is meant to showcase tagging and search.  Needless to say, some “classic” email users are used to the folder views, preview panes and other such needs.  With the help of the almighty Google, I have figured out how to take some of the “hate” against of the Gmail and move the anger down to a low-simmer.

First off, these options require Chrome.  Using Chrome instead of IE is the first step.  After that, extensions can get us the rest of the way.

Option #1

One way, and possibly the easiest way is to use the Gmail Offline Chrome extension.

The bad news: It’s a bit different again from the original Gmail interface and requires a different link and shortcut (which is the biggest barrier).

The good news: It works without an internet connection.

Option #2

Enable the preview window in Gmail’s Labs.

Mashable has a good post on how to enable the preview window by:

  1. Go to the Gmail Gear settings menu
  2. Click on Labs
  3. Search for Preview Pane
  4. Click the Enable radio button
  5. Click Save
  6. Show your inbox with the pane by clicking the new button in the top right hand side

Yea!  You have a preview pane.  But wait!  There is a lot of annoying white space being used for a “Person Widget.”  Personally, I do not care how many circles a person is in.  I want to email them, not post to their wall.

Remove the Person Widget

You can remove the Person widget by going back into settings.

  1. Go to the Gmail Gear settings menu
  2. Click the disable radio button under People Widget
  3. Scroll to the bottom of the page and Click Save

There. It is gone.  But is it?  The white space is still there.  Gah!  The circles will never leave me alone!  Good news though.  This reduces page requests to Google and speeds up the Gmail experience slightly.

Get Rid of That White Space by Overriding Some CSS

Chrome to the rescue!  By using an extension, we can make everything go all the way to the end of the screen and give us what we’re really after.

The extension is Personalized Web.

The steps to destroy this blasphemy of circles interrupting our workflow are as follows:

  1. Install Personalized Web
  2. Go to your Chrome wrench and then go to Tools > Extensions
  3. Find Personalized Web and click options
  4. Now that it is in edit mode, add a new rule
  5. Name = Gmail
    Match URL = https://mail.google.com
    Add the following to the CSS field
        .Bu:nth-child(2) { display:none; }
        .Bu:nth-child(3) { display:none; } 
  6. Click Save
  7. Refresh Gmail
  8. Celebrate

Then the person widget is totally gone and everything looks great!

Whew!  That was a lot of work.  Now, just by logging into Gmail, you get the preview pane you want and not have to worry about different links or worry about clicking the wrong shortcut.   It works great and will hopefully make everyone a bit happier.