Building Browsergames: Implementing an e-mail confirmation system (Perl)

For all that you probably don’t need a user’s e-mail address, there are still some times where you want to have users confirm their e-mail address. So today, we’ll go through how to build an e-mail verification system in Perl.

To begin with, we’ll use the code from our Perl registration page. We start off by adding two columns to our users table – one to track the user’s e-mail address, and another column to track whether they’ve actually confirmed their e-mail address yet or not:

ALTER TABLE  `users` ADD  `email` TEXT NOT NULL;
ALTER TABLE `users` ADD `confirmed` tinyint(1) NOT NULL DEFAULT 0;

The first thing we will do is add an input box to our code for the user’s e-mail address:

44
45
E-mail Address: <input type='text' name='email' /><br />
<input type='submit' value='Register!' />

Perl, unlike PHP, doesn’t have a built-in function for sending mail. So we’ll be printing messages to a program called sendmail in order to send our e-mail. If you’re on a linux host, it’s generally a safe bet that they have sendmail installed – although if they don’t, you can always send their support team an e-mail and ask if they can set it up for you. I am not sure if windows hosts have sendmail – but once again, try e-mailing their support and figuring it out that way.

All we’re going to actually change in our code is how the registration process occurs – now, when a user registers, their e-mail will be stored and they’ll be sent a quick e-mail to say “hey, click here to confirm your e-mail address!”:

30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
			$sth = $dbh->prepare("INSERT INTO users(username,password,email) VALUES (?,?,?)");
			$sth->execute($arguments{username},crypt($arguments{password},$arguments{username}),$arguments{email});
			my $subject = "Subject: browsergame e-mail address confirmation\n";
			my $sendmail = '/usr/sbin/sendmail -t';
			my $reply_to = "Reply-to: webmaster\@example.com\n";
			my $content_type = "Content-type: text/html; charset=iso-8859-1\n\n";
			my $content = qq ~
<p>Hey! Thanks for signing up for the browsergame. Click below to confirm your e-mail address.</p>
<p><a href='http://website.com/confirm.cgi?email=$arguments{email}'>below</a></p>
			~;
			open(SENDMAIL, "| $sendmail") or die "Could not open $sendmail: $!";
			print SENDMAIL $reply_to, $subject, "To: $arguments{email}\n", $content_type, $content;
			close(SENDMAIL);			
			$html .= qq ~
<span style='color:green'>Congratulations! You registered successfully!</span>			
			~;

And that should send the user an e-mail after they register.

Now, it’s important to mention something – you should always be testing to make sure that the e-mail address supplied to you is valid before you try to send something to it. A malicious user could do all sorts of things with sendmail, if they got access to it. One way to do this is by using the module Email::Valid:

7
8
9
10
11
12
13
14
15
16
17
18
use Email::Valid;
 
my $query = new CGI;
my %arguments = $query->Vars;
my $html;
unless(Email::Valid->address($arguments{email})) {
	print $query->header();
	print "You supplied an invalid e-mail address.";
	exit;	
}
 
if(%arguments) {

And with that all finished, we can move on to our confirmation page – which is what will actually mark a user as ‘confirmed’ after they click on the link in the e-mail we sent to them.

The confirm page is pretty simply – all it does is take in an e-mail address(or any other unique attribute), and use it to update a specific user’s information within the database:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/usr/bin/perl -w
 
use strict;
use CGI qw(:cgi);
use CGI::Carp qw(fatalsToBrowser warningsToBrowser);
use config;
 
my $query = new CGI;
my %arguments = $query->Vars;
my $output;
if(%arguments) {	
	my $dbh = DBI->connect("DBI:mysql:$dbname:$dbhost",$dbuser,$dbpass,{RaiseError => 1});
	my $sth = $dbh->prepare("SELECT count(id) FROM users WHERE email = ? AND confirmed = 0");
	my $count;
	$sth->execute($arguments{email});
	$sth->bind_columns(\$count);
	$sth->fetch;
	if($count >= 1) {
		$sth = $dbh->prepare("UPDATE users SET confirmed=1 WHERE email = ?");
		$sth->execute($arguments{email});
		$output = qq ~
<span style='color:green'>Congratulations, you've confirmed your e-mail address!</span>		
		~;
	} else {
		$output = qq ~
<span style='color:red'>Oops! Either that user doesn't exist, or that e-mail address has already been confirmed.</span>		
		~;	
	}
}
print $query->header();
print $output;

There isn’t much to this code that you haven’t seen before – as a matter of fact, there isn’t anything in this code that you haven’t seen before. All it does is take the supplied e-mail and check it against the database, updating whether a user is confirmed or not if it’s in there and unconfirmed. If it’s already been confirmed, it spits out a helpful error message.

And that’s all that’s involved in adding e-mail confirmation to your registration system! Here’s the revised registration page code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#!/usr/bin/perl -w
 
use strict;
use CGI qw(:cgi);
use CGI::Carp qw(fatalsToBrowser warningsToBrowser);
use DBI;
use Email::Valid;
 
my $query = new CGI;
my %arguments = $query->Vars;
my $html;
 
if(%arguments) {
	unless(defined $arguments{email} && Email::Valid->address($arguments{email})) {
		print $query->header();
		print "You supplied an invalid e-mail address.";
		exit;	
	}
	if($arguments{password} ne $arguments{confirm}) {
		$html .= qq ~
<span style='color:red'>Error! Those passwords do not match!</span>	
		~;	
	} else {
		use config;
		my $dbh = DBI->connect("DBI:mysql:$dbname:$dbhost",$dbuser,$dbpass,{RaiseError => 1});
		my $sth = $dbh->prepare("SELECT count(id) FROM users WHERE UPPER(username) = UPPER(?)");
		$sth->execute($arguments{username});
		my $count;
		$sth->bind_columns(\$count);
		$sth->fetch;
		if($count >= 1) {
			$html .= qq ~
<span style='color:red'>Error: that username is taken.</span>			
			~;	
		} else {
			$sth = $dbh->prepare("INSERT INTO users(username,password,email) VALUES (?,?,?)");
			$sth->execute($arguments{username},crypt($arguments{password},$arguments{username}),$arguments{email});
			my $subject = "Subject: browsergame e-mail address confirmation\n";
			my $sendmail = '/usr/sbin/sendmail -t';
			my $reply_to = "Reply-to: webmaster\@example.com\n";
			my $content_type = "Content-type: text/html; charset=iso-8859-1\n\n";
			my $content = qq ~
<p>Hey! Thanks for signing up for the browsergame. Click below to confirm your e-mail address.</p>
<p><a href='http://website.com/confirm.cgi?email=$arguments{email}'>below</a></p>
			~;
			open(SENDMAIL, "| $sendmail") or die "Could not open $sendmail: $!";
			print SENDMAIL $reply_to, $subject, "To: $arguments{email}\n", $content_type, $content;
			close(SENDMAIL);			
			$html .= qq ~
<span style='color:green'>Congratulations! You registered successfully!</span>			
			~;	
		}
	}
}
 
$html .= qq ~
<form method='post' action='register-email.cgi'>
Username: <input type='text' name='username' /><br />
Password: <input type='password' name='password' /><br />
Confirm Password: <input type='password' name='confirm' /><br />
E-mail Address: <input type='text' name='email' /><br />
<input type='submit' value='Register!' />
</form>
~;
 
print $query->header();
print $html;

And here’s the confirmation page code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/usr/bin/perl -w
 
use strict;
use CGI qw(:cgi);
use CGI::Carp qw(fatalsToBrowser warningsToBrowser);
use config;
 
my $query = new CGI;
my %arguments = $query->Vars;
my $output;
if(%arguments) {	
	my $dbh = DBI->connect("DBI:mysql:$dbname:$dbhost",$dbuser,$dbpass,{RaiseError => 1});
	my $sth = $dbh->prepare("SELECT count(id) FROM users WHERE email = ? AND confirmed = 0");
	my $count;
	$sth->execute($arguments{email});
	$sth->bind_columns(\$count);
	$sth->fetch;
	if($count >= 1) {
		$sth = $dbh->prepare("UPDATE users SET confirmed=1 WHERE email = ?");
		$sth->execute($arguments{email});
		$output = qq ~
<span style='color:green'>Congratulations, you've confirmed your e-mail address!</span>		
		~;
	} else {
		$output = qq ~
<span style='color:red'>Oops! Either that user doesn't exist, or that e-mail address has already been confirmed.</span>		
		~;	
	}
}
print $query->header();
print $output;

If you want to see it in action, you can check it out at the sample Perl e-mail registration page, where the code you see above is being run.

Wish there was more?

I'm considering writing an ebook - click here.

.

Luke is the primary editor of Building Browsergames, and has written a large portion of the articles that you read here. He generally has no idea what to say when asked to write about himself in the third person.

Monday, May 12th, 2008 buildingbrowsergames, code, perl
blog comments powered by Disqus

About

Building Browsergames is a blog about browsergames(also known as PBBG's). It's geared towards the beginner to intermediate developer who has an interest in building their own browsergame.

Sponsors

Got Something to Say?

Send an e-mail to luke@buildingbrowsergames.com, or get in touch through Twitter at http://twitter.com/bbrowsergames