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.
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.



