FormMail Troubleshooting Guide

Still running FormMail.pl on your server? Here are solutions to every common error, plus a migration guide to modern alternatives.

Matt Wright’s FormMail was the web’s most popular CGI script, but in 2026 it’s also one of the most problematic. Hosting providers like xneelo have discontinued FormMail support entirely. Whether you need to fix a broken installation or migrate to something modern, this guide covers both paths.

1. “Bad Referer — Access Denied”

This is the single most common FormMail error. When someone submits your form, FormMail checks whether the referring page’s domain is in its allowed list. If not, it blocks the request.

What You See

Bad Referer - Access Denied
The form attempting to use this script resides at
www.yourdomain.com, which is not allowed to access
this program.

Cause

The @referers array inside FormMail.pl does not include the domain that hosts your HTML form. FormMail compares the HTTP_REFERER header against this list and rejects anything that doesn’t match.

Fix: Add Your Domain to @referers

Open FormMail.pl in a text editor and find the @referers line near the top of the file. Add your domain, including both the bare domain and the www version:

# Before (default)
@referers = ('yourdomain.com');

# After (include www variant)
@referers = ('yourdomain.com', 'www.yourdomain.com');

Fix 2: HTTP vs HTTPS Mismatch

If your site recently moved to HTTPS, the referer header now sends https://www.yourdomain.com instead of http://. Some older FormMail versions compare the full URL including protocol. The solution is either:

  • Upgrade to a version that strips the protocol before comparison, or
  • Ensure the @referers array only contains domain names (not full URLs), which FormMail v1.6 should match correctly

Fix 3: Check for Trailing Slashes

Some browsers send referer headers with trailing paths. Make sure you’re matching the domain, not a specific page URL. The @referers array should contain just the hostname:

# Wrong
@referers = ('www.yourdomain.com/contact.html');

# Correct
@referers = ('yourdomain.com', 'www.yourdomain.com');
Tip: If you host multiple sites on the same server and they all use one FormMail installation, add every domain to the @referers array. Wildcard entries like '*.yourdomain.com' are not supported in the original FormMail — you need to list each subdomain explicitly.

2. “500 Internal Server Error”

A 500 error means the server could not execute the script at all. The actual cause is always in the server error log. Check /var/log/httpd/error_log (Apache) or /var/log/nginx/error.log (Nginx) first. Below are the four most common reasons.

Cause 1: Wrong Perl Path

The first line of FormMail.pl (the shebang) tells the server where to find the Perl interpreter. If the path is wrong, the script cannot execute.

# Common paths — only ONE of these is correct for your server
#!/usr/bin/perl
#!/usr/local/bin/perl
#!/usr/bin/env perl

To find the correct path on your server:

$ which perl
/usr/bin/perl

Use whatever which perl returns as your shebang line. On most modern Linux servers, #!/usr/bin/perl is correct. On FreeBSD and some shared hosting, #!/usr/local/bin/perl is typical. The safest portable option is #!/usr/bin/env perl, which searches the system PATH.

Cause 2: Windows Line Endings (CRLF)

If you edited FormMail on Windows and uploaded it via FTP in binary mode, the file will contain \r\n (CRLF) line endings instead of Unix \n (LF). The Perl interpreter will choke on the carriage return characters.

Fix: Re-upload using ASCII transfer mode in your FTP client, or convert line endings on the server:

# Convert CRLF to LF
$ dos2unix FormMail.pl

# Or with sed:
$ sed -i 's/\r$//' FormMail.pl

# Or with Perl itself:
$ perl -pi -e 's/\r\n/\n/g' FormMail.pl

Cause 3: Wrong File Permissions

CGI scripts must be executable by the web server. FormMail.pl needs 755 permissions (owner: read/write/execute, group and others: read/execute).

# Check current permissions
$ ls -la FormMail.pl
-rw-r--r-- 1 user group 12345 Jan 01 00:00 FormMail.pl

# Fix: make executable
$ chmod 755 FormMail.pl

# Verify
$ ls -la FormMail.pl
-rwxr-xr-x 1 user group 12345 Jan 01 00:00 FormMail.pl

On some shared hosting, the cgi-bin directory itself also needs 755 permissions, and the files inside must be owned by your user account (not root).

Cause 4: Missing Sendmail Binary

FormMail uses the sendmail command to deliver email. The $mailprog variable at the top of the script must point to a valid sendmail (or sendmail-compatible) binary:

# Default in FormMail.pl
$mailprog = '/usr/lib/sendmail';

# Common correct paths
$mailprog = '/usr/sbin/sendmail';    # Most modern Linux
$mailprog = '/usr/bin/sendmail';     # Some distributions
$mailprog = '/usr/local/bin/msmtp';  # If using msmtp

Find it on your server:

$ which sendmail
/usr/sbin/sendmail

If which sendmail returns nothing, sendmail is not installed. You’ll need to install it (yum install sendmail on RHEL/CentOS, apt install sendmail on Debian/Ubuntu) or switch to an SMTP-based alternative.

3. “Blank Page (No Output)”

You submit the form and get a completely blank page — no error, no confirmation, nothing. This is almost always a missing or malformed HTTP content-type header.

Cause: Missing Content-Type Header

CGI scripts must output a Content-type header before any HTML body. If the script crashes or exits before printing this header, the web server returns a blank page (or sometimes a 500 error, depending on the server configuration).

Diagnostic Steps

  1. Run FormMail from the command line to see raw output:
    $ cd /var/www/yourdomain.com/cgi-bin/
    $ perl FormMail.pl
    Content-type: text/html
    
    (If you see this header, the script starts correctly)
  2. Check for syntax errors in the Perl code:
    $ perl -c FormMail.pl
    FormMail.pl syntax OK

    If you see errors instead of “syntax OK,” fix the reported line numbers.

  3. Check the error log for “Premature end of script headers”:
    $ tail -20 /var/log/httpd/error_log | grep -i formmail

    This error means the script died before outputting the required Content-type line.

Common Fixes

  • If the script has a syntax error, fix it — a single missing semicolon can cause a blank page
  • Make sure you have not accidentally deleted the print "Content-type: text/html\n\n"; line in FormMail.pl
  • If you customized the $success_url or $error_url variables and they point to pages that do not exist, FormMail may redirect to a blank or 404 page
  • Perl module dependencies: if someone modified the script to use CGI.pm or other modules, verify they are installed with perl -e "use CGI; print 'OK'"

4. “Mail Not Received”

The form submits successfully, you may even see the “thank you” page, but the email never arrives. This is increasingly common as mail servers tighten spam filtering.

Cause 1: Wrong Sendmail Path

FormMail displays its confirmation page before checking whether sendmail actually delivered the message. The form appears to work, but the email silently fails. Verify $mailprog points to a valid binary (see Section 2, Cause 4).

Cause 2: Spam Filter Blocking

Emails sent by FormMail via sendmail often lack proper authentication (no SPF, no DKIM, no DMARC). Modern email providers like Gmail, Outlook, and Yahoo will likely:

  • Route the message to spam/junk folder
  • Silently drop it entirely (especially Gmail)
  • Bounce it with a “550 SPF check failed” error

Fix: Check your spam/junk folder first. Then check the mail queue on the server:

# Check if mail is queued
$ mailq

# Check mail log for delivery status
$ tail -50 /var/log/maillog | grep yourdomain

# Test sendmail manually
$ echo "Subject: Test" | sendmail -v [email protected]

Cause 3: Server Does Not Have Sendmail

Some modern hosting environments (containers, minimal VPS images) do not ship with sendmail installed. If which sendmail returns nothing, you have three options:

  1. Install sendmail or Postfix: yum install postfix or apt install postfix
  2. Install a lightweight alternative like msmtp that relays through an external SMTP server (Gmail, Mailgun, etc.)
  3. Migrate to a form handler that uses SMTP directly (see Migration Guide)

Cause 4: @recipients Restriction

In NMS FormMail and some patched versions of the original, the @recipients or @allow_mail_to array restricts which email addresses FormMail is allowed to send to. If the recipient address in your form’s hidden recipient field is not in this list, the email is silently dropped.

# Check this array in FormMail.pl
@allow_mail_to = ('[email protected]', '[email protected]');

5. “FormMail Used for Spam”

This is the most serious FormMail problem. If attackers discover your FormMail installation, they can use it to send spam to any email address — turning your server into an open relay.

If this is happening to you right now: Remove or rename FormMail.pl immediately. Every minute it stays accessible, your server is sending spam and your IP reputation is dropping.

How It Works

Matt Wright’s FormMail v1.0–1.6 has two critical vulnerabilities:

  • CVE-2001-0357 — Email Header Injection: Attackers inject %0ABcc: (a CRLF followed by a BCC header) into form fields like email or subject. FormMail passes this directly to sendmail, adding arbitrary recipients to every message.
  • CVE-2002-0564 — Open Relay: The recipient hidden field can be set to any email address. Without proper validation, attackers submit the form with [email protected] and send email to anyone.

Spammers routinely scan the web for /cgi-bin/FormMail.pl and /cgi-bin/formmail.pl using automated bots. Even if your FormMail has been sitting untouched for years, it can be discovered and exploited within days of being accessible.

Immediate Actions

  1. Remove the script: mv FormMail.pl FormMail.pl.disabled
  2. Check your mail queue: mailq | head -50 — if there are thousands of queued messages, flush them: postsuper -d ALL
  3. Check your IP reputation: Visit MXToolbox Blacklist Check and enter your server IP
  4. Review access logs for POST requests to FormMail:
    $ grep -i "formmail" /var/log/httpd/access_log | tail -20
  5. Block future requests in your web server config:
    # Apache .htaccess
    <Files "FormMail.pl">
        Require all denied
    </Files>
    
    # Nginx
    location ~* formmail\.pl$ {
        deny all;
        return 403;
    }

Long-Term Fix

If you need a Perl form handler, replace Matt Wright’s version with NMS FormMail (version 1.93 or later), which validates recipients against a whitelist and sanitizes all header fields. Better yet, migrate to a modern alternative entirely. See the full security history for technical details on each vulnerability.

6. “My Hosting Provider Removed FormMail”

An increasing number of hosting providers are actively removing FormMail from their servers and disabling legacy CGI support. This is not a bug — it is a deliberate security decision.

Known Providers That Have Dropped FormMail

Provider Date Details
xneelo (Hetzner South Africa) November 30, 2025 Announced end of FormMail support; recommended migrating to PHP or third-party form services
InMotion Hosting 2024 Removed legacy CGI scripts from new accounts; existing accounts can still use cgi-bin but without support
Pair Networks 2023 Deprecated Perl CGI in favor of PHP and Python-based solutions
Various cPanel Hosts Ongoing cPanel’s “CGI Center” no longer ships with FormMail since cPanel 100+

Your Options

  1. Ask your host if they support custom CGI scripts. If yes, you can install NMS FormMail in your own cgi-bin directory.
  2. Switch to PHP — most shared hosting supports PHP natively. A basic PHP contact form is 20 lines of code.
  3. Use a form backend service like Formspree or Web3Forms — no server-side code needed at all. See the Migration Guide below.

If your existing forms stopped working overnight, your host likely removed or blocked CGI execution. Check your hosting control panel for any announcements, or contact support. Do not try to “fix” a hosting-level restriction — migrate instead.

7. Migration Guide: What to Use Instead of FormMail

FormMail was revolutionary in 1995. In 2026, there are better options that are more secure, require less server configuration, and actually deliver emails reliably. Here are the most practical replacements, ranked by ease of migration.

Option 1: Formspree (Easiest Migration)

Formspree is a form backend service. You change one line in your HTML (the action attribute) and your form works. No server-side code, no sendmail, no Perl. Free tier: 50 submissions per month.

<!-- Before: FormMail -->
<form action="/cgi-bin/FormMail.pl" method="POST">
  <input type="hidden" name="recipient" value="[email protected]">
  <input type="hidden" name="subject" value="Contact Form">
  <input type="text" name="name" placeholder="Your Name">
  <input type="email" name="email" placeholder="Your Email">
  <textarea name="message"></textarea>
  <button type="submit">Send</button>
</form>

<!-- After: Formspree (change action, remove hidden fields) -->
<form action="https://formspree.io/f/YOUR_FORM_ID" method="POST">
  <input type="text" name="name" placeholder="Your Name">
  <input type="email" name="email" placeholder="Your Email">
  <textarea name="message"></textarea>
  <button type="submit">Send</button>
</form>

Migration time: 5 minutes per form. Sign up, get your form ID, update the HTML.

Option 2: Web3Forms (Free, No Account Required)

Web3Forms provides a free form API. You include an access key as a hidden field and point the form action to their endpoint. No registration wall — just enter your email to get an API key.

<form action="https://api.web3forms.com/submit" method="POST">
  <input type="hidden" name="access_key" value="YOUR_ACCESS_KEY">
  <input type="text" name="name" required>
  <input type="email" name="email" required>
  <textarea name="message" required></textarea>
  <button type="submit">Send</button>
</form>

Migration time: 5 minutes. Free tier: 250 submissions per month.

Option 3: Basin

Basin is another form endpoint service with a generous free tier (100 submissions/month). It supports file uploads, spam filtering, and webhook integrations.

<form action="https://usebasin.com/f/YOUR_FORM_ID" method="POST">
  <input type="text" name="name" required>
  <input type="email" name="email" required>
  <textarea name="message" required></textarea>
  <button type="submit">Send</button>
</form>

Option 4: Netlify Forms (If Hosted on Netlify)

If your site is on Netlify, form handling is built in. Add netlify to the form tag and Netlify automatically collects submissions. Free tier: 100 submissions per month.

<form name="contact" method="POST" data-netlify="true">
  <input type="text" name="name" required>
  <input type="email" name="email" required>
  <textarea name="message" required></textarea>
  <button type="submit">Send</button>
</form>

Option 5: PHP mail() (Server-Side Alternative)

If you need server-side form handling and your host supports PHP (virtually all do), a simple PHP script replaces FormMail entirely:

<?php
// contact.php — minimal form handler
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $to      = '[email protected]';
    $subject = 'Contact Form: ' . htmlspecialchars($_POST['subject'] ?? 'No Subject');
    $name    = htmlspecialchars($_POST['name'] ?? '');
    $email   = filter_var($_POST['email'] ?? '', FILTER_VALIDATE_EMAIL);
    $message = htmlspecialchars($_POST['message'] ?? '');

    if ($email && $message) {
        $body    = "From: $name <$email>\n\n$message";
        $headers = "From: $email\r\nReply-To: $email";
        mail($to, $subject, $body, $headers);
        header('Location: /thank-you.html');
        exit;
    }
}
header('Location: /contact.html?error=1');
?>

Point your form’s action to contact.php instead of FormMail.pl. This is the most direct server-side replacement.

Option 6: NMS FormMail (Drop-In Perl Replacement)

If you specifically need a Perl CGI form handler (for example, other systems depend on FormMail’s output format), the NMS Project provides a secure drop-in replacement. NMS FormMail v1.93+ patches all known vulnerabilities while maintaining the same configuration interface.

# Download NMS FormMail
$ wget https://sourceforge.net/projects/nms-cgi/files/nms-formmail/
$ cp NMSFormMail-*.pl /var/www/yourdomain.com/cgi-bin/FormMail.pl
$ chmod 755 /var/www/yourdomain.com/cgi-bin/FormMail.pl

# Edit the configuration variables at the top of the file:
# - Set @allow_mail_to to your email addresses
# - Set @referers to your domains
# - Set $mailprog to your sendmail path

Comparison Table

Solution Cost Server Required Migration Time Spam Protection
Formspree Free (50/mo) No 5 min Built-in
Web3Forms Free (250/mo) No 5 min Built-in
Basin Free (100/mo) No 5 min Built-in
Netlify Forms Free (100/mo) Netlify only 2 min Built-in
PHP mail() Free Yes (PHP) 15 min Manual (add reCAPTCHA)
NMS FormMail Free Yes (Perl) 10 min Basic validation

Frequently Asked Questions

The “Bad Referer” error means the domain hosting your HTML form is not listed in the @referers array inside FormMail.pl. Open the script, find the @referers line, and add your domain — both with and without www. Also verify whether your site uses HTTP or HTTPS, as the referer header includes the protocol. See Section 1 for detailed steps.

A 500 error in FormMail has four common causes: wrong Perl interpreter path in the shebang line, Windows CRLF line endings, incorrect file permissions (needs chmod 755), or a missing sendmail binary. Check your server’s error log first — it will tell you the exact cause. See Section 2 for fixes for each scenario.

No. Matt Wright’s original FormMail.pl (versions 1.0 through 1.6) has known, actively exploited vulnerabilities: CVE-2001-0357 (email injection) and CVE-2002-0564 (open relay). Spammer bots still scan for FormMail installations daily. If you must use a Perl form handler, use NMS FormMail v1.93 or later. For most use cases, a modern service like Formspree or Web3Forms is a safer and easier choice. Read the full security history for details.

Several categories of tools have replaced FormMail:

  • Form backend services (no server needed): Formspree, Web3Forms, Basin
  • Platform-native forms: Netlify Forms, Vercel Forms, Cloudflare Workers
  • Server-side scripts: PHP mail(), Python Flask/Django form handlers, Node.js with Nodemailer
  • Secure Perl replacement: NMS FormMail (drop-in replacement with security fixes)

See the Migration Guide above for code examples and a comparison table.

The migration takes about five minutes per form:

  1. Sign up at formspree.io and create a new form to get your endpoint URL
  2. In your HTML, change the <form action="..."> from the CGI path to your Formspree URL
  3. Remove FormMail-specific hidden fields (recipient, subject, redirect, etc.) — Formspree handles these through its dashboard settings
  4. Make sure every <input> and <textarea> has a name attribute — Formspree uses these as field labels in the email
  5. Test the form by submitting it once and checking your inbox

See the before/after code example above for the exact HTML changes.

Quick Diagnostic Checklist

Run through this checklist when debugging any FormMail issue. Each step takes 30 seconds or less.

# Check Command Expected Result
1 Perl is installed which perl /usr/bin/perl
2 Shebang matches head -1 FormMail.pl Matches which perl output
3 Permissions are 755 ls -la FormMail.pl -rwxr-xr-x
4 No syntax errors perl -c FormMail.pl syntax OK
5 Unix line endings file FormMail.pl No “CRLF” in output
6 Sendmail exists which sendmail /usr/sbin/sendmail
7 @referers includes your domain grep '@referers' FormMail.pl Your domain is listed
8 $mailprog path is correct grep '$mailprog' FormMail.pl Matches which sendmail
9 CGI execution is enabled curl -I https://yourdomain.com/cgi-bin/ Not 403 Forbidden
10 Error log shows the cause tail -20 /var/log/httpd/error_log Check for Perl/CGI errors

Related Resources

FormMail.pl Documentation

Complete documentation for Matt Wright’s FormMail v1.6: configuration variables, form fields, installation guide, and download.

FormMail Security History

How FormMail became the internet’s biggest spam tool: CVE-2001-0357, CVE-2002-0564, and the NMS Project response.

Download All Scripts

Download every script from Matt’s Script Archive in one package, including FormMail, Guestbook, WWWBoard, and more.