October 21

11 comments

Example RPG Email Validation program – SQLRPGLE ILE

By NickLitten

October 21, 2020

RPG, email, expression, IBM i, regex, regular, snippet, SQL, SQLRPGLE

Let’s look at a quick little example RPG email validation program – SQLRPGLE ILE

There are lots of code snippets, example programs, and long waffling discussions in internet land filled with pointy-headed AS400, Series, and IBM i programmer chaps (and chappettes) arguing about the best way to “validate an email address in RPG”.

I know because I’ve read nearly all of them, as well as tried all the techniques.

But yesterday I stumbled across a really simple variation of an established technique that seems to work 99% of the time (note: there is no perfect validation expressions since email address rules are changing frequently)

Using Regex to validate an email

Look at this SQLRPGLE code snippet:

exec sql
    set :myCount = regexp_count( :myEmail, '^(?:\w+\.?)*\w+@(?:\w+\.)*\w+$');

If myCount = 1;
   // email is good 
else;
   // email is malformed 
endif;

Pretty simple huh!

So , what are we doing with this regular expression?

The regular expression ‘^(?:\w+\.?)*\w+@(?:\w+\.)*\w+$‘ is saying – check this input string meets the standard of something before an @ sign followed by something dot something:

Example rpg

The internet is filled with alternate regular expressions to make the email validation logic as complex as you wish.

For my purposes this simple logic is exactly what I need.

So, let’s plumb this into an example RPG program, wrapped in a tidy sub-procedure, with a sprinkling of comments, my favorite QUILNGTX *API for display screen messages without coding any DSPF and using variable-length characters –  just for fun (Yes, I know, I need to get out more):

**free
// --------------------------------------------------------------
Rpg code snippet// Example SQL RPG program : VLD8EMAIL
// Author : Nick Litten
// ? CRTSQLRPGI ??OBJ(LITTENN/VLD8EMAIL)
//   SRCFILE(LITTENN/QRPGLESRC)
//   SRCMBR(VLD8EMAIL)
//   OBJTYPE(*PGM)
// History:
// 2012-06-12 NJL Created
// --------------------------------------------------------------
// This program accepts an input parameter of 'email address'.
// We validate it using a regular expression in SQL and
// display a message in a window telling you if the email
// address is good or bad. nice or naughty.
// Simple but Saucy.
// --------------------------------------------------------------

ctl-opt dftactgrp(*no) ccsid(*CHAR:37) actgrp('VALIDATE') option(*nodebugio:*srcstmt);

// this is our program input a 255 character variable containg the email address
dcl-pi *n;  
  email char(255);
end-pi;

// this is our subprocedure - put this in a *SRVPGM to share it
dcl-pr email_is_valid IND; 
  *n like(email);
end-pr;

if email_is_valid(email);
  display_window ('Email Address ' + %trim(email) + ' is valid');
else;
  display_window ('Yuk! Email Address ' + %trim(email) +  ' failed email address validation!');
endif;

*inlr = *on;
return;


// --------------------------------------------------------------
// PROCEDURE: email_is_valid
// --------------------------------------------------------------
// Accept an input field (the email address) and validate it using
// a regular expression to perform basic email address syntax checks.
//
// REGEXP_COUNT Returns a returns a count of the number of times
// that a regular expression pattern is matched in a string
//
// The leading ^ and trailing $ match the beginning and the ending of
// the input string, respectively. That is, the entire input string
// shall match with this regexe, instead of a part of the input string.
//
// \w+ matches 1 or more word characters (a-z, A-Z, 0-9 and underscore).
//
// [.-] matches character . or -. We need to use . to represent . as . has
// special meaning in regexe. The \ is known as the escape code, which
// restore the original literal meaning of the following character.
//
// [.-]? matches 0 or 1 occurrence of [.-].
//
// ([.-]?\w+)* matches 0 or more occurrences of [.-]?\w+.
//
// The sub-expression \w+([.-]?\w+)* is used to match the username in
// the email, before the @ sign. It begins with at least one word
// character (a-z, A-Z, 0-9 and underscore), followed by more word
// characters or . or -. However, a . or - must follow by a word
// character (a-z, A-Z, 0-9 and underscore). That is, the string cannot
// contain "..", "--", ".-" or "-.". Example of valid string are "a.1-2-3".
//
// The @ matches itself.
//
// The sub-expression .\w{2,3} matches a . followed by two or three word
// characters, e.g., ".com", ".edu", ".us", ".uk", ".co".
//
// (.\w{2,3})+ specifies that the above sub-expression shall occur one or
// more times, e.g., ".com", ".co.uk", ".edu.sg" etc.
// --------------------------------------------------------------

dcl-proc email_is_valid;
dcl-pi *n IND;
  myEmail like(email);
end-pi;
dcl-s myCount uns(10);

// you can change this Regex string to anything you like!!!
dcl-s myEmailValidationRegex varchar(1024)
      inz('^(?:\w+\.?)*\w+@(?:\w+\.)*\w+$');

exec sql
   set :myCount = regexp_count(:myEmail,:myEmailValidationRegex);

 If myCount = 1;
   return *on;
 else;
   return *off;
 endif;

end-proc;

// --------------------------------------------------------------
// PROCEDURE: display_window 
// --------------------------------------------------------------
// Use IBM i *API 'QUILNGTX' to dynamically show messages in a 
// window format rather than on the error message line 
// --------------------------------------------------------------
dcl-proc display_window export;
 dcl-pi display_window;
   p_Text varchar(8192) const;
   p_MsgId char(7) Options(*nopass: *omit);
   p_MsgFile char(21) Options(*nopass: *omit);
 end-pi;

 dcl-ds myApiError inz qualified;
   Bytes int(10) inz(%size(myApiError));
   BytesAvailable int(10) inz;
   ErrorID char(7) inz;
   Reserved char(1) inz(x'00');
   MessageData char(128) inz;
 end-ds;

 dcl-pr QUILNGTX extpgm('QUILNGTX');
   *n char(8192) const;
   *n int(10) const;
   *n char(7) const;
   *n char(21) const;
   *n options(*omit: *varsize) like(myapierror);
 end-pr;

 dcl-s myMsgId like(p_MsgId);
 dcl-s myMsgFile like(p_MsgFile);

 If %Parms = 1;
   myMsgId = 'CPF9999';
   myMsgFile = 'QCPFMSG';
 Elseif %Parms = 2;
   myMsgId = p_MsgId;
   myMsgFile = 'QCPFMSG';
 Elseif %Parms = 3;
   myMsgId = p_MsgId;
   myMsgFile = p_MsgFile;
 Endif ;

 QUILNGTX ( p_Text : %Len(p_Text) : myMsgId : myMsgFile : myApiError );

end-proc;

I hope that helps someone out?

Let’s test this SQLRPGLE code

Testing is easy – I just knocked together a little calling program, because calling variable-length input parameters from an IBM i command line is painful. Convert the previous code into a *SRVPGM (or copy/paste the code into the mainline) to add it to this example and:

**free
// Example SQL RPG program : TESTEMAIL
// Author : Nick Litten
// ? CRTSQLRPGI ??OBJ(LITTENN/TESTEMAIL)
//   SRCFILE(LITTENN/QRPGLESRC)
//   SRCMBR(TESTEMAIL)
//   OBJTYPE(*PGM)
// History:
// 2014-06-12 NJL Created
// --------------------------------------------------------------
// call validation program with various VARCHAR email addresses
// --------------------------------------------------------------

ctl-opt dftactgrp(*no)
        actgrp('VALIDATE')
        option(*nodebugio:*srcstmt);

dcl-pr tst_email extpgm('VLD8EMAIL'); 
  *n varchar(255); 
end-pr; 

dcl-s email varchar(255); 

email = 'nick@nicklitten.com'; 
tst_email(email); 

email = 'nick@this-is_a@very$duff email'; 
tst_email(email); 

*inlr = *on;

and when I call my TEST program I see these two sceeens:

Example rpg email validation program - sqlrpgle ile 1
Example rpg email validation program - sqlrpgle ile 2

PS: to test your regular expressions check out http://emailregex.com/regex-visual-tester/ it’s excellent!

Hope that helps some out?


Update Oct 2020

A new regex is shown over at email regex – I would love to know if this helps anyone?

General Email Regex (RFC 5322 Official Standard)

1(?:[a-z0-9!#$%&’*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&’*+/=?^_`{|}~-]+)*|”(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*”)@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])

  • Nice work documenting and commenting, as well as including a usable subprocedure and test. Do you know whether IBM’s SNDSMTPEMM supports recipient email addresses with the “.bz” domain? The command throws a TCP530F Email Address Invalid whenever I try to use it with “.bz” domains.

      • (?:[a-z0-9!#$%&’*+/=?^_`{|}~-]+(?:.[a-z0-9!#$%&’*+/=?^_`{|}~-]+)*|”(?:[x01-x08x0bx0cx0e-x1fx21x23-x5bx5d-x7f]|\[x01-x09x0bx0cx0e-x7f])*”)@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[x01-x08x0bx0cx0e-x1fx21-x5ax53-x7f]|\[x01-x09x0bx0cx0e-x7f])+)])

  • I’m trying to implement the Email Validation on a Power 9, V7R3, up to date PTF’s. I copied the source programs and compiled without any changes. Every email address I try to validate returns as invalid, showing the email address with a preceding ‘?’: ?nick@nicklitten.com Any suggestions on how to remove the ‘?’. I believe that’s the cause of all the failures. Thanks.

    • that happened to me when I was calling the program from the command line. Once I called the program from another program it worked just fine.

      • Javier just email me saying the problem was because it was users with different CCSID on their profiles. I just updated the code sample to specify a CCSID of 37. Let’s see if that fixes this quirkiness?

        ps: Thanks Javier!

  • Hi… I was able to make the program to work and test the email address. But for some weird reason when I run my program to test the email it works fine returning either 1 or 0 but for other users the count is always sent back as 0 even when the email is correct. I just do not get what is the reason.

  • {"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}

    Join the IBM i Community for FREE Presentations, Lessons, Hints and Tips

    >