No description
Find a file
2020-02-26 17:49:59 -05:00
README.md README quote all env vars 2020-02-26 17:49:59 -05:00
server.go Fix SMPT->SMTP typo in env var reading 2020-02-26 17:41:47 -05:00
test.html Add back test.html page 2020-02-25 22:03:02 -05:00

Simple Contact Form Email Server (SCFES)

This has the purpose of listening for POST requests from a "contact me" or "contact us" form on a static webpage. It will log these in a Postgres database and also email them to whomever should be notified.

This server is developed to be run on a debian 9 server running nginx and PostgreSQL. Go was chosen as the scripting language, because its built in http server is considered "safe" to expose to the greater internet. The same cannot be said about Python. And I don't like nodejs...

Setup

This assumes you have a go dev environment running go>=1.10.

Server Executable

First get all required dependencies and builds into an executable, then copy it to a good location. It is possible to cross compile this executable from a local go dev environment and copy it to the server if go cannot be easily installed. Run this as a non-privlaged user with a valid go environment:

go get -u gitlab.com/pleune/simple-contact-form-email-server
sudo sh -c "mkdir -p /usr/local/bin && cp '$GOPATH/bin/simple-contact-form-email-server' /usr/local/bin/scfes"

Database

Install PostgreSQL, and create a database and user for this site (if you have not already for other purposes)

  • See the debian setup page. Think about using the user www-data (nginx user) or even creating a new user.
  • Need to setup a "comments" table:
    CREATE TABLE comments (id SERIAL PRIMARY KEY, name VARCHAR(100) NOT NULL, email VARCHAR(100), sendingip INET, referer VARCHAR(1024), time TIMESTAMP NOT NULL, message VARCHAR NOT NULL)
    

Nginx

Setup a forwarding rule in your Nginx configuration:

For example, put this in /etc/nginx/sites-enabled/default.conf:

location /contact {
  proxy_pass          http://localhost:8456;
  proxy_set_header    X-Real-IP       $remote_addr;
  proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
}

Systemd Service

All configuration options are passed to the server through environment variables.

/etc/scfes.conf:

SCFES_LISTEN=":8456"
SCFES_SMTP_SERVER="YourSmtpServerAddress"
SCFES_SMTP_PORT="587"
SCFES_SMTP_USER="YourSmtpServerUsername"
SCFES_SMTP_PASS="YourSmtpServerPassword"
SCFES_FROM="no-reply@example.com"
SCFES_TO="you@gmail.com"
SCFES_SUBJECT="Contact from example.com"
SCFES_PG_CONNSTR="dbname=exampledotcom user=www-data password=yourpassword sslmode=disable"

/etc/systemd/system/scfes.service:

[Unit]
Description=Simple Contact Form Email Server (SCFES)
After=network.target

[Service]
User=nobody
EnvironmentFile=/etc/scfes.conf
ExecStart=/usr/local/bin/scfes

[Install]
WantedBy=multi-user.target

Install everything (as root):

# Because the config file has secrets in it,
# remove read rights from it:
chmod 600 /etc/scfes.conf
systemctl enable scfes.service
systemctl start scfes.service

Updating

Here is a snippet to quickly update the server:

go get -u gitlab.com/pleune/simple-contact-form-email-server &&
sudo systemctl stop scfes.service &&
sudo sh -c "mkdir -p /usr/local/bin && cp '$GOPATH/bin/simple-contact-form-email-server' /usr/local/bin/scfes" &&
sudo systemctl start scfes.service &&
echo "Update Successful..."

Server Code

This is an example form:

<form method="post" action="/contact">
  <label for="name">Name</label>
  <input type="text" name="name" id="name" /> <br />
  <label for="email">Email</label>
  <input type="email" name="email" id="email" /> <br />
  <label for="message">Message</label>
  <textarea name="message" id="message" rows="4"></textarea> <br />
  <input type="submit" value="Send Message" />
</form>

Here is some JQuery to highlight fields in red if they are returned as invalid, and prevents redirection on submit:

var $contact = $('#contact')
var $name = $contact.find('#name')
var $email = $contact.find('#email')
var $message = $contact.find('#message')
var name_default_border = $name.css('border-color')
var email_default_border = $email.css('border-color')
var message_default_border = $message.css('border-color')
$contact.submit(function (event) {
event.preventDefault()

  var f = $(this)
  var url = f.attr('action')

  $.ajax({
    type: 'POST',
    url: url,
    data: f.serialize()
  })
  .fail(function (jqXHR, textStatus) {
    var data = ((typeof jqXHR.responseText === 'string') ? jqXHR.responseText : " ")

    var badname = data.includes('badname')
    var bademail = data.includes('bademail')
    var badmessage = data.includes('badmessage')

    if (badname)
      $name.css('border-color', 'red')
    else
      $name.css('border-color', name_default_border)

    if (bademail)
      $email.css('border-color', 'red')
    else
      $email.css('border-color', email_default_border)

    if (badmessage)
      $message.css('border-color', 'red')
    else
      $message.css('border-color', message_default_border)

    if (!badname && !bademail && !badmessage)
      alert('An error occurred that prevented your message from being processed.')
  })
  .done(function (data) {
    $name.css('border-color', name_default_border)
    $email.css('border-color', email_default_border)
    $message.css('border-color', message_default_border)
    $message.val('')
    alert('Your comment has been successfully processed.\r\nThank You!')
  })
})