Skip navigation

Tag Archives: gmail

Gmail-like email compsoe window

There might come a time when you would like to borrow some Gmail features to create a page or popup to send an email or create some kind of editable text body.  Since I have wanted several Gmail-like features in a couple of projects I wanted to share one way of accomplishing some of the cool features Gmail has like tokenizeing email address, auto-complete and editable text areas.

Since this guide is intended to get beginners up to speed quickly as well as avoid reinventing the wheel, I will use Jquery-tokeninput and nicEdit. There are other tokenizers/autocomplete out there, as well as other WYSIWYG editors, but I felt that these two were both easy to use, very hackable and had MIT licenses if you work for a company that worrys about licenses.

I looked into several WYSIWYG editors (rather than create one from scratch), I found that I like nicEdit better, it was exteremly easy to integrate, their webpage lets you customize it to a certainextent and it is MIT licncesned.The downsides are that there are bugs and nicEdit is no longer being maintanied. The upside is that there are many forks on github.

First thing you need to do is make sure you a webserver with PHP setup. Once you have that setup and running, we will start to build our page.  Make sure you have downloaded jQuery and nicEdit (or one of the nicEdit forks on github). I will start by  creating a file called send_email.php:

<!DOCTYPE html>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
	<title>Gmail Clone Example</title>
	<link rel="shortcut icon" href="favicon.ico">
	<link rel="stylesheet" type="text/css" href="send_email.css" />	
<style>
</style>

<script src="jquery-2.0.1.min.js"></script>
<script src="send_email.js"></script>

</head>
<body id="body_email">

<?php

if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'send' ) {
	$missing_error = 0;

	if (isset($_REQUEST['subject'])) {
		$subject = $_REQUEST['subject']; 
	}

	if (isset($_REQUEST['body'])) {
		$body = $_REQUEST['body'];
        }

	if (isset($_REQUEST['to'])) {
		$to = $_REQUEST['to'];
        }

	if (isset($_REQUEST['cc'])) {
		$cc = $_REQUEST['cc'];
        }

	if (isset($_REQUEST['bcc'])) {
		$bcc = $_REQUEST['bcc'];
        }

	//send email
	$headers  = 'MIME-Version: 1.0' . PHP_EOL;
	$headers .= 'Content-type: text/html; charset=iso-8859-1' . PHP_EOL;
	$headers .= 'From: Me <me@email.com>' . PHP_EOL;
	$headers .= 'Bcc: ' . $bcc . PHP_EOL; 
	$headers .= 'Cc: ' . $cc . PHP_EOL;

	mail($to, $subject, $body, $headers);

	//post success message

}
$html = '
	<div id="content">
		<!--- To Email Addresses --->
		<div>
			<div class="email_address_label"><span>' . _("To") . ': </span></div>
			<div class="email_address_wrapper">
				<div id="to" class="email_addresses">
					<input type="text" id="to_manuals" class="manual_email_addresses"/>
					</div>
				</div>
			</div>

			<!--- CC Email Addresses --->
			<div class="cc_container_div">
				<div class="email_address_label"><span>' . _("CC") . ': </span></div>
				<div class="email_address_wrapper">
					<div id="cc" class="email_addresses">
						<input type="text" id="cc_manuals" class="manual_email_addresses"/>
					</div>
				</div>
			</div>

			<!--- BCC Email Addresses --->
			<div class="bcc_container_div">
				<div class="email_address_label"><span>' . _("BCC") . ': </span></div>
				<div class="email_address_wrapper">
						<div id="bcc" class="email_addresses">
								<input type="text" id="bcc_manuals" class="manual_email_addresses"/>
						</div>
				</div>
			</div>

			<!--- BCC/CC BUTTONS --->
			<div>
				<div class="add_cc_label"><span>&nbsp;</span></div>
				<div class="add_cc_wrapper">
					&nbsp;
					<button id="add_cc" class="add_cc">
						' . _("Add CC") . '
					</button>
					<button id="add_bcc" class="add_bcc">
						' . _("Add BCC") . '
					</button>
					&nbsp;
				</div>
			</div>

			<!--- Subject --->
			&nbsp;
			<div>
				<div class="email_subject_label"><span>' . _("Subject") . ': </span></div>
				<div class="email_subject_wrapper">
					<input type="text" id="subject" class="subject"/>
				</div>
			</div>
			<!--- BODY TEXT --->
			<!--- BODY HTML --->
			<div>
				<div class="email_body_html_label"><span>' . _("Body") . ': </span></div>
				<div class="email_body_html_wrapper">
					<textarea cols="64" name="email_body_html" id="email_body_html" class="email_body_html" ></textarea>

				</div>
			</div>

			<!--- Send/Clear BUTTONS --->
			<div>
				<div id="button_bar">
					<button id="send">' . _("Send") . '</button>
				</div>
			</div>
		</div>
	';

echo $html;

?>
</body>
</html>

Your jQuery version might be different from the one I used, make sure to replace jquery-2.0.1.min.js with the file you have downloaded.

So now we have the basic form with some PHP to handle sending emails, so lets go ahead and make the CSS so this displays better and make the JS code to hide the BCC/CC buttons and fire the send email clicked event.

I’ll name the css file send_email.css

 

# {
	position:         absolute;
	top:              0px;
	left:             0px;
	right:            0px;
	bottom:           0px;
	overflow:         hidden;
}

#content {
	position:         absolute;
	top:              60px;
	left:             60px;
	right:            60px;
	bottom:           60px;
	padding:          5px;
	padding-right:    6px;
	overflow:         auto;
	border:           1px solid rgba(30, 30, 30, .2);
}

.email_address_label {
	float:           left;
	width:           10%;
}

.email_address_label span {
	position:        relative;
	top:             5px;
	font-weight:     600;
}

.email_address_wrapper {
	float:           left;
	width:           90%;
}

.email_addresses {
	display:          inline-block;
	position:         relative;
	width:            100%;
	min-height:       30px;
}

.email_addresses input {
	width:   100%;
	border: 2px solid #dadada;
	padding:         0px;
	box-shadow:      none;
}

.email_addresses input:focus {
	outline: none;
	border-color: #9ecaed;
	box-shadow: 0 0 10px #9ecaed;
}

.manual_email_addresses {
	position:         absolute;
	top:              2px;
	left:             2px;
	bottom:           2px;
	right:            200px;
	background-color: rgba(255, 255, 255, 0.4);
}

.email_subject_label {
	 float:           left;
	 width:           10%;
}

.email_subject_label span {
	 position:        relative;
	 top:             5px;
	 font-weight:     600;
}

.add_cc_label {
	float:           left;
	width:           10%;
}

.add_cc_label span {
	position:        relative;
	top:             5px;
}

.email_body_html_label {
	 float:           left;
	 width:           10%;
}
.email_body_html_label span {
	 position:        relative;
	 top:             5px;
	 font-weight:     600;
}

.email_subject_wrapper {
	 float:           left;
	 width:           90%;
	spellcheck:     true;
}

.email_subject_wrapper input {
	width: 100%;
	border: 2px solid #dadada;
	padding:         0px;
	box-shadow:      none;
}

.email_subject_wrapper input:focus {
	width: 100%;
	outline: none;
	border-color: #9ecaed;
	box-shadow: 0 0 10px #9ecaed;
}

.add_cc_wrapper {
	float:           left;
	width:           90%;
}

.email_attachments_wrapper {
	 float:           left;
	 width:           90%;
}

.email_attachments_wrapper button {
	position:        relative;
	margin-top:      2px;
	height:          26px;
}

.email_attachments_wrapper button span {
	position:        relative;
	bottom:          2px;
}

.email_body_html_wrapper {
	float:           left;
	width:           90%;
	spellcheck:     true;
}

.email_body_html_wrapper textarea {
	height:          100px;
	width:           100%;
	max-width:       100%;
}

div.nicEdit-panel {
	width: 100% !important;
}

.nicEdit-panelContain {
	width: 100% !important;
}

 

So lets write up the JS file now, I named mine send_email.js

window.onload = function() {

	//Hide intial CC feild and show the button, onclick hide the button and show feild
	$(".cc_container_div").hide();
	$(".add_cc").click(function() {
		$(".cc_container_div").show();
		$(".add_cc").hide();
	});

	//Do the same for BCC
	$(".bcc_container_div").hide();
	$(".add_bcc").click(function() {
		$(".bcc_container_div").show();
		$(".add_bcc").hide();
	});

	$('#send').click(handleSendClick);	

};

/**
* Handles a click of the Send button.
*/
var handleSendClick = function(event) {
	var confirm_msg = 'Are you sure you would like to send this message?';
	var missing_msg = '';
	var missing_count = 0;

	var my_subject = $('#subject').val();
	var my_body = $('#email_body_html').val(); 
	var my_to = $('#to_manuals').val();

	if (my_subject.length == 0) {
		missing_msg += 'subject';
		missing_count++;
	}

//length is not zero bug
	if (my_body.length == 0) {
		if (missing_msg.length)
			missing_msg += ', ';
		missing_msg += 'body';
		missing_count++;
	}

	if (my_to.length == 0) {
		if (missing_msg.length)
			missing_msg += ', ';
		missing_msg += 'to';
		missing_count++;
	}

	if (missing_count) {
		//capitalize first letter
		if (missing_count == 1)
			missing_msg += ' feild is empty, would you like to send anyway?';
		else 
			missing_msg += ' feilds are empty, would you like to send anyway?';
		confirm_msg = missing_msg;
	}

	if (confirm(confirm_msg)) {
		var form = document.createElement("form");
		form.setAttribute("method", "post");
		form.setAttribute("action", "send_email.php?action=send");

		var params = new Array();
		params['subject'] = my_subject;
		params['body'] = my_body;
		params['to'] = my_to;
		params['cc'] = $('#cc_manuals').val();
		params['bcc'] = $('#bcc_manuals').val();
		params['fileuids'] = $('#attachments').val();

		for(var key in params) {
			if(params.hasOwnProperty(key)) {
				var hiddenField = document.createElement("input");
				hiddenField.setAttribute("type", "hidden");
				hiddenField.setAttribute("name", key);
				hiddenField.setAttribute("value", params[key]);
				form.appendChild(hiddenField);
			}
		}
		document.body.appendChild(form);
		form.submit();
	}
}

Okay, so now we should have  a page that looks quite simliar to gmails email composing page. When the user clicks on “Add CC” the “Add CC” button should disappear and the div holding our CC field should appear, same goes with Bcc.

I should also talk about sending emials in PHP, you might want to use a third party (such as Amazon SES) but if you decide to use the server that PHP is running mail() works quite well. You can configure PHP to use itself (localhost) or an external sendmail server.

I chose the easy route for this guide, but as you copy and paste realize that wrapping mail() in a class would be a better choice design wise.

 

Gmail-like E-mail compose screen

 

Now let’s start enhancing this by adding the Tokenizer functions. In send_email.js we will add:

      $("#to_manuals").tokenInput("emailLookup.php?q=", {
                theme: "facebook",
                tokenValue: "name",
                resultsFormatter: function(item) {
                        return "<li><div style=\'display: inline-block; padding-left: 10px;\'><div class=\'email_row\'>" + item.first_name + " " + item.last_name + " &lt;" + item.name + "&gt;" + "</div></div></li>";
                },
                tokenFormatter: function(item) {
                        return "<li><p>" + item.displayname + "</b></p></li>";
                },
                preventDuplicates: false
        });

        $("#cc_manuals").tokenInput("emailLookup.php?q=", {
                theme: "facebook",
                tokenValue: "name",
                resultsFormatter: function(item) {
                        return "<li><div style=\'display: inline-block; padding-left: 10px;\'><div class=\'email_row\'>" + item.first_name + " " + item.last_name + " &lt;" + item.name + "&gt;" + "</div></div></li>";
                },
                tokenFormatter: function(item) {
                        return "<li><p>" + item.displayname + "</b></p></li>";
                },
                preventDuplicates: false
        })

        $("#bcc_manuals").tokenInput("emailLookup.php?q=", {
                theme: "facebook",
                tokenValue: "name",
                resultsFormatter: function(item) {
                        return "<li><div style=\'display: inline-block; padding-left: 10px;\'><div class=\'email_row\'>" + item.first_name + " " + item.last_name + " &lt;" + item.name + "&gt;" + "</div></div></li>";
                },
                tokenFormatter: function(item) {
                        return "<li><p>" + item.displayname + "</b></p></li>";
                },
                preventDuplicates: false
        })

We will also create a file to handle our database lookup named emailLookup.php. In my version I just created a fake example of hard-coded email addresses. You should get a little creative and make database calls or API calls to your favorite database.

<?php

class EmailLookup {
        private $emails = array( array('chuck', 'wolfe', 'chuckwolfe@email.com'),
                                        array('Susan', 'Orville', 'sorville@pops.com'),
                                        array('Stacy', 'Lacey', 'slacey@doamin.com'),
                                        array('Brad', 'Humchucker', 'captainStan@rideglide.com'),
                                        array('Herbert', 'Stankiver', 'mayorbob@ymail.com'),
                                        array('Cat', 'Manchester', 'Cmanchester@email.com'));

        private function contains($array_unit, $term) {
                if (stripos($array_unit[0], $term) !== false)
                        return true;
                if (stripos($array_unit[1], $term) !== false)
                        return true;
                if (stripos($array_unit[2], $term) !== false)
                        return true;
                return false;
        }

        private function queryEmails($search_term) {
                $email_addresses = array();

                foreach ($this->emails AS $email) {
                        $email_address = array();
                        if ($this->contains($email, $search_term)) {
                                $email_address['first_name'] = $email[0];
                                $email_address['last_name'] = $email[1];
                                $email_address['displayname'] = $email[0] . " " . $email[1];

                                $email_address['name'] = $email[2];
//had to use name, since i couldn't format my results with 'email'
//seems it only has support for name and id
                                $email_addresses[] = $email_address;
                        }
                }
                print json_encode($email_addresses);
        }

        function __construct($search_term) {
                //do i need to inti this list?
                //$email_list = new emailList();
                $this->queryEmails($search_term);
        }

}

$email_lookup = new EmailLookup($_REQUEST['q']);
?>

 

 

Screen Shot 2013-08-17 at 1.00.19 PM

Now we have nice tokenized email addresses. You can customize this further, Loopj is designed so you can change the color, the orientation (vertical lists or horizontal lists), you could show an avatar next to each persons name, or show other data like how many times you email them, or if they are a current employee, whatever data you have about them you could show somehow, it is a very nice script. Of course other tokeizners are easier to use and lighterweight.

Now we need to add a WYSIWYG editor. WYSIWYG means What You See Is What You Get. I’m writing this blog post in a WYSIWYG right now using WordPress.
Add PHP, js, etc

Add to send_email.js:

nicEditors.allTextAreas();

This enables text editors on every text area in you page, in our case this is okay since we only have one text area. If your page has more than one text area and you do not want an editor in it you would not use this method.

 

Gmail-like email compsoe window

 

 

 

This concludes my tutorial. The source can be found on github here. Feel free to ask questions in the comment section, thank you.