Software, your way.
How To Get Good Custom Software
(Download)
(PDF)
burger menu icon
WillMaster

WillMaster > LibraryWebsite Email

FREE! Coding tips, tricks, and treasures.

Possibilities weekly ezine

Get the weekly email website developers read:

 

Your email address

name@example.com
YES! Send Possibilities every week!

Light Mailer

You have a list of people you want to email — maybe less than a hundred, maybe up to several thousand.

If you're doing only one mailing, it may not be too much of a job to send each one separately with your trusty email software, or via gmail or other webmail site. But if you intend to send email to the list a few times, or frequently for an extended period, mailing individually would become an onerous task.

Using BCC for the list of addresses to lighten the task can cause deliverability issues. The spam flags at ISPs may be raised because the "To:" address is not the destination.

And using CC for the list of addresses would reveal every email address to every recipient — not a good practice.

The kicker is that you're not making money, or very little, from the list. You prefer not to assume the cost of a professional mailing service at this time.

Introducing Light Mailer

The free one-file Light Mailer software installs on your server. You paste in your list of recipient addresses, provide the email content particulars, and tap "send".

A version of Light Mailer is used at the Willmaster website for some mailings. The Willmaster version sends email via the Mailgun service.

The version of Light Mailer that comes free with this article sends email via the PHP built-in mail() function so no email sending service needs to be engaged.

A very, very important caveat: Light Mailer type of software is a spammer magnet.

Although Light Mailer has security designed to prevent unauthorized email from being sent, it is still prudent to install the software in a password-protected directory — or upload the software file to your server only when you are ready to use it, then delete the file immediately afterward.

Light Mailer Features

When pasting destination email addresses into the mailing form, you don't have to be overly concerned with formatting. The software is designed to extract email addresses pretty much any way you want to paste them into the form, even if they are mixed in with additional text.

The software can send plain text or HTML email. If HTML, it must have HTML markup so it doesn't get delivered as one run-in block of text.

This screenshot of the dashboard reveals other Light Mailer features, including how easy it is to use.

Light Mailer Screenshot

To use, fill in the form and tap the button.

Before sending email, however, there are things to be aware of that are likely to affect how you compose your email and/or how you fill in the form to send it.

Potential Sending and Delivering Issues

A person can do some things to comply with certain email sending restrictions your hosting account may have and to make email more likely to be delivered to the destination and land in the inbox (rather than in a junk folder).

Sending Email Restrictions

Depending on your hosting company and type of account you have, sending email from your server may have restrictions.

This is especially likely for shared accounts. I've heard of 500/day limits. And 50/hr limits.

Virtual private server (VPS) accounts, even if outgoing email is not otherwise regulated, may have concurrent connection limits. These limits may be exceeded when the connections are slammed with several hundred outgoing emails all at once.

For number-of-emails-per-day limits, a person would need to limit their list size so they don't send more than the limit. When determining list size, consider how many emails other software on your server may need to send — contact form handling software, for example.

The Light Mailer software has a feature to help you stay within number-of-emails-per-hour limits. It lets you pause the mailing for a specific number of seconds between each email sent out. (The customization instructions in the Installing Light Mailer section have a calculator for the number of seconds.)

The pause-between-emails feature can also be used to slow down the mailing if exceeding available concurrent connection limits are a concern.

The "From:" Address

For better deliverability, the "From:" address in the email header should be of the same domain as the domain where the email is sent from. As an example, if the email is sent from the www.willmaster.com server then name@willmaster.com is of the same domain.

When you want replies sent to an address at a different domain than where the email was sent from, specify a "Reply‑to:" address for that.

Links in the Email

For better deliverability, any links in the email should be to the same domain as the domain where the email is sent from.

When you need to link to a URL different than the sending domain, redirect software can be used. Short URL V3 installed at the sending domain can both redirect the tap to the correct destination and count the number of taps on that link in your email.

Installing Light Mailer

The install the software, copy the Light Mailer source code from the box below and save it as file name LightMailer.php or other preferred *.php file name.

Then make the customizations. (Customization notes follow the source code.)

To use Light Mailer, upload the software to your server, type its URL into your browser, fill in the form, and tap the "Send Email" button. It is best security to upload the software into a password-protected directory.

<?php
/*
Light Mailer
Version 1.0, January 4, 2018
Version 1.1, June 20, 2019
    (Added 2nd security check and email address 
    extraction when mixed within other content)
Version 1.2, June 21, 2019 (Added sending delay)

Will Bontrager Software LLC
https://www.willmaster.com/
*/

 /******************/
/* Customizations */

/*
For security, specify at least two addresses that 
must be included in the list of destination email 
addresses before a mailing will happen. If only 1
address is available for use here then specify it 
for both email address checks.
*/

$EmailAddress1forSecurityCheck = 'name1@example.com';
$EmailAddress2forSecurityCheck = 'name2@example.com';


/*
Specify the number of seconds to delay between the sending of 
each email. The digit 0 is acceptable for specifying 0 delay.
*/

$DelayBetweenSendings = 2;


/*
Between the lines that contain the word HEADERLINES
specify any header lines to include in the outgoing 
email. Blank lines are allowed here.
*/

$HeaderLines = <<<HEADERLINES

X-Mailer: Light Mailer v1.2

HEADERLINES;

 /* End of customizations */
/*************************/

mb_regex_encoding('UTF-8');
mb_internal_encoding('UTF-8');
if( ! ini_get('date.timezone') ) { date_default_timezone_set('UTC'); }
$Errors = array();
$DestinationList = array();
foreach( array('addylist', 'fromaddy', 'fromname', 'replytoaddy', 'replytoname', 'emailsubject', 'format', 'emailcontent') as $k )
{
    if( empty($_POST[$k]) ) { $_POST[$k] = ''; }
}
if( isset($_POST['send']) )
{
    foreach( array('addylist', 'fromaddy', 'emailsubject', 'emailcontent') as $k )
    {
        if( empty($_POST[$k]) ) { $Errors[] = "The field with form field name $k needs information."; }
    }
    if( empty($_POST['send_verification']) ) { $Errors[] = 'The "send email" checkbox needs to be checked.'; }
    if( $_POST['fromaddy'] and (!preg_match('/[\w\.\-\_]\@[\w\.\-\_]+\.[\w\.\-\_]/',$_POST['fromaddy'])) ) { $Errors[] = 'The From: email address is invalid.'; }
    if( $_POST['replytoaddy'] and (!preg_match('/[\w\.\-\_]\@[\w\.\-\_]+\.[\w\.\-\_]/',$_POST['replytoaddy'])) ) { $Errors[] = 'The Reply-to: email address is invalid.'; }
}
if( $_POST['send'] and (!count($Errors)) )
{
    $matches = array();
    preg_match_all('/([\w\.\-\_]+\@[\w\.\-\_]+\.[\w\.\-\_]+)/',$_POST['addylist'],$matches);
    foreach( $matches[1] as $addy ) { $DestinationList[strtolower($addy)] = true; }
    ksort($DestinationList);
    if( empty($DestinationList[strtolower($EmailAddress1forSecurityCheck)]) or empty($DestinationList[strtolower($EmailAddress2forSecurityCheck)]) )
    {
        $Errors[] = 'A security check was not passed.';
        unset($_POST['send']);
    }
}
if( count($Errors) ) { unset($_POST['send']); }
$DelayBetweenSendings = intval($DelayBetweenSendings) > 0 ? intval($DelayBetweenSendings) : false;
?>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Light Mailer</title>
<style type="text/css">
html, body { font-size:100%; font-family:sans-serif; line-height:120%; }
#content { max-width:6in; margin:.5in auto; }
input[type=text], input[type=submit], textarea, select { width:100%; line-height:120%; box-sizing:border-box; font-size:1em; border:1px solid #ccc; padding:.5em; border-radius:.5em; font-family:sans-serif; background-color:#efefef; }
input[type=checkbox] { margin:0; }
table { border-collapse:collapse; margin:0 auto; }
p, td { font-size:1em; }
th { font-size:.8em; line-height:110%; }
.bold { font-weight:bold; }
.italic { font-style:italic; }
.underline { text-decoration:underline; }
.normalfont { font-style:normal; font-weight:normal; text-decoration:none; }
.nowrap { white-space:nowrap; }
a { text-decoration:none; }
.above-field { margin-bottom:2pt; }
</style>
</head>
<body><div id="content">
<form method="post" enctype="multipart/form-data" accept-charset="utf-8" action="<?php echo($_SERVER['PHP_SELF']) ?>">
<h1>Light Mailer</h1>
<?php
if( isset($_POST['send']) )
{
    $headers = array();
    foreach( preg_split('/[\r\n]/',trim($HeaderLines)) as $hline )
    {
        if( strpos($hline,':')===false )
        {
            $ta = explode(' ',$hline);
            $h = array_shift($ta);
            $headers[$h] = implode(' ',$hline);
        }
        else
        {
            list($k,$v) = explode(':',$hline);
            $k = str_replace(' ','-',trim($k));
            $v = trim($v);
            $headers[$k] = $v;
        }
    }
    $headers['MIME-Version'] = '1.0';
    $headers['Content-type'] = "text/{$_POST['format']}; charset='UTF-8'";
    $headers['From'] = $_POST['fromname'] ? "\"{$_POST['fromname']}\" <{$_POST['fromaddy']}>" : $_POST['fromaddy'];
    if($_POST['replytoaddy']) { $headers['Reply-to'] = $_POST['replytoname'] ? "\"{$_POST['replytoname']}\" <{$_POST['replytoaddy']}>" : $_POST['replytoaddy']; }
    $ta = array();
    foreach( $headers as $k => $v ) { $ta[] = "$k: $v"; }
    $headerchunk = implode("\r\n",$ta);
    $subject = trim($_POST['emailsubject']);
    $content = str_replace( "\n", "\r\n", str_replace("\r\n","\n",$_POST['emailcontent']) );
    echo <<<MAILINGCOMMENCE
<div style="border:3px double blue; padding:1em; border-radius:6px; color:blue; font-weight:bold;">
<p style="margin-top:0;">Mailing commences now. Destinations list follows.</p>
MAILINGCOMMENCE;
    foreach( $DestinationList as $addy => $bool )
    {
        echo "<p style='margin:0 0 0 1em;'>$addy</p>";
        mail($addy,$subject,$content,$headerchunk);
        flush();
        if( $DelayBetweenSendings ) { sleep($DelayBetweenSendings); }
    }
    echo '<p style="margin-bottom:0;">Mailing completed.</p></div>';
}
?>
<?php if(count($Errors)): ?>
<div style="border:3px double red; padding:1em; border-radius:6px; color:red; font-weight:bold;">
<p style="margin-top:0; font-weight:bold;">Ouch:</p>
<ul style="margin-bottom:0;">
<li><?php echo(implode('</li><li>',$Errors)) ?></li>
</ul>
</div>
<?php endif; ?>
<p>
Fields marked with * are required.
</p>
<p class="above-field" style="margin-left:.8em; text-indent:-.8em;">
<span class="bold">*</span> The "To:" destination address or list of addresses. Email addresses may be mixed in within other content, in which case the software will try to extract them.
</p>
<textarea name="addylist" style="height:1in;"><?php echo(htmlspecialchars($_POST['addylist'])) ?></textarea>

<div style="border-left:3px solid #ccc; border-radius:1em; padding-left:.75em;">
<p class="above-field" style="margin-left:.8em; text-indent:-.8em;">
<span class="bold">*</span> From: email address.
</p>
<input type="text" name="fromaddy" value="<?php echo(htmlspecialchars($_POST['fromaddy'])) ?>">

<p class="above-field">
From: name.
</p>
<input type="text" name="fromname" value="<?php echo(htmlspecialchars($_POST['fromname'])) ?>">
</div>

<div style="border-left:3px solid #ccc; border-radius:1em; padding-left:.75em;">
<p class="above-field">
Reply-to: email address.
</p>
<input type="text" name="replytoaddy" value="<?php echo(htmlspecialchars($_POST['replytoaddy'])) ?>">

<p class="above-field">
Reply-to: name.
</p>
<input type="text" name="replytoname" value="<?php echo(htmlspecialchars($_POST['replytoname'])) ?>">
</div>

<p class="above-field" style="margin-left:.8em; text-indent:-.8em;">
<span class="bold">*</span> Email subject line.
</p>
<input type="text" name="emailsubject" value="<?php echo(htmlspecialchars($_POST['emailsubject'])) ?>">

<p class="above-field" style="margin-left:.8em; text-indent:-.8em;">
<span class="bold">*</span> Email content. <span class="nowrap">(Send as 
<input type="radio" name="format" value="plain" <?php if($_POST['format']=='plain'){echo('checked="checked"');} ?>>Text 
<input type="radio" name="format" value="html" <?php if($_POST['format']!='plain'){echo('checked="checked"');} ?>>HTML)</span>
</p>
<textarea name="emailcontent" style="height:4in;"><?php echo(htmlspecialchars($_POST['emailcontent'])) ?></textarea>

<p>
<input type="submit" name="send" value="Send Email" style="background-color:red; color:white;">
<input type="checkbox" name="send_verification" value="yes"> (Check required to send email)
</p>

<p style="margin-top:2em;">
Copyright 2018-2019 <a href="https://www.willmaster.com/">Will Bontrager Software LLC</a>
</p>
<div style="height:1in;"></div>

</div>
</body>
</html>

Customizations —

The Light Mailer source code has 3 sections to customize. The first section is required. The rest may be left as is.

  1. This customization is for security, intended to flummox unauthorized use of Light Mailer.

    Find these two lines in the Light Mailer source code:

    $EmailAddress1forSecurityCheck = 'name1@example.com';
    $EmailAddress2forSecurityCheck = 'name2@example.com';
    

    Replace name1@example.com and name2@example.com with two email addresses that must be somewhere in the list of destinations before the emailing can be accomplished. (If you only have one email address available for that, put the address in both places; but be aware that specifying the same one email address can reduce security.)

  2. It may be necessary or desirable to slow down the mailing. Some reasons were described at Sending Email Restrictions section earlier in this article.

    Find this line in the Light Mailer source code:

    $DelayBetweenSendings = 2;
    

    Replace 2 with the number of seconds to delay between the sending of each email. Use the digit 0 to specify no delay.

    Here is a calculator to determine the number of seconds to delay when a maximum number of emails per hour are allowed.

    Number of emails per hour that are allowed:

     

    Seconds pause between emails: _____

    If other software on your server may be sending email at the same time, increase the pause by 1 or more seconds.

  3. Custom header lines may be specified. Mailer identification and unsubscribe URL may be desired, as examples. Email identification is another example. It is entirely up to you what to include.

    Header lines are composed of label and value. The label comes first and is composed of alphanumeric characters that may include hyphens and underscore characters. The label is followed with a : colon character and a space (which is the first space on the line). The rest of the line is the value.

    Find these lines in the Light Mailer source code:

    $HeaderLines = <<<HEADERLINES
    
    X-Mailer: Light Mailer v1.2
    
    HEADERLINES;
    

    Between the lines that contain the word HEADERLINES, specify any header lines to include in the outgoing email.

Sending Notices

When you tap the "Send Email" button, the page will reload and you'll see the email addresses being sent to. As each email address is sent to, the address adds itself to the list. If you specified a pause between email sendings, there will be that amount of pause between when addresses are added to the sent list.

Light Mailer does a good job for as simple as it is to use. The security and other features under the hood make it rather sophisticated for such a short script.

(This article first appeared with an issue of the Possibilities newsletter.)

Will Bontrager

Was this article helpful to you?
(anonymous form)

Support This Website

Some of our support is from people like you who see the value of all that's offered for FREE at this website.

"Yes, let me contribute."

Amount (USD):

Tap to Choose
Contribution
Method

All information in WillMaster Library articles is presented AS-IS.

We only suggest and recommend what we believe is of value. As remuneration for the time and research involved to provide quality links, we generally use affiliate links when we can. Whenever we link to something not our own, you should assume they are affiliate links or that we benefit in some way.

How Can We Help You? balloons
How Can We Help You?
bullet Custom Programming
bullet Ready-Made Software
bullet Technical Support
bullet Possibilities Newsletter
bullet Website "How-To" Info
bullet Useful Information List

© 1998-2001 William and Mari Bontrager
© 2001-2011 Bontrager Connection, LLC
© 2011-2024 Will Bontrager Software LLC