## Send mail through WordPress (without using SMTP plugins)

WordPress itself does not provides SMTP settings to configure in the admin area.

But there are two ways that you can send mail from WordPress:

1. By using plugins that set up SMTP connections to outside mail servers.
2. Or by using WordPress’ internal wp_mail() function, which defaults to using PHP’s mail() function, fully relying on PHP’s settings to handle mail.

To send mail via wp_mail(), WordPress uses an internal PHPMailer class which sets some default values.

The included PHPMailer class defaults to using PHP’s mail() function, but can also instead connect to your mail account (e.g., gmail) directly.

To use the mail() function, you’ll need to enable and configure MSMTP to establish a local SMTP proxy/forwarding to a real mail server or mail account (such as gmail).

Then edit file –
wp-includes\class-phpmailer.php

Change…

public $From = 'root@localhost'; public$Host = 'localhost';
public $SMTPAutoTLS = true; To… public$From = 'name@gmail.com';
public $Host = '127.0.0.1'; public$SMTPAutoTLS = false;

The above settings is for a local SMTP proxy such as MSMTP or for a local SMTP server.

If you want to connect to gmail directly, change “$Mailer” to “SMTP” and update settings accordingly. ## Debugging SMTP Issues Check the website’s HTTP and PHP error log files, and the general PHP error log file for logged PHP errors. Check PHP’s mail() function log and MSMTP’s log file to make sure that email is not being rejected because the header/from is invalid. PHP mail log – C:\WampDeveloper\Logs\Php\maillog.txt MSMTP mail log – C:\WampDeveloper\Tools\msmtp\msmtplog.txt ## Optimized WAMP Setting For Increased Performance ## OS Layer If your OS is a server edition, does not contain other software (such as active anti-virus programs), has a clean network layer, and has network drivers that are not broken, enable the use of the OS’s abilities to speed up memory access, file delivery, and network access. Enable the use of: 1. Sending static files to the client without reading those files by using Apache directive EnableSendfile. EnableSendfile On 2. Memory mapped files to provide a more direct access to files by using Apache directive EnableMMAP. EnableMMAP On This works better for delivering larger files, than smaller files. 3. OS API AcceptEx() rather than Accept() to optimize socket handling, and recycle sockets between connections, by using Apache directive AcceptFilter. <IfVersion < 2.3> # Make sure this is commented out # Win32DisableAcceptEx </IfVersion> <IfVersion >= 2.3.3> AcceptFilter http data AcceptFilter https data </IfVersion> All the above settings are stored in file – \WampDeveloper\Config\Apache\extra\wampd-default.conf Save file and restart Apache for changes to take effect. These setting can create operational problems such as: random issues with pages not being loaded or being loaded half way, Apache crashes, and in some cases performance degradation. WampDeveloper Pro defaults to turning all of these settings Off for stability and compatibility reasons, with the possible trade-off in performance. ### Interfering Software To prevent slowdowns, make sure to exclude the Apache, PHP, and MySQL processes and WAMP folder from anti-virus (and related software) scanning. The database files, the temporary folder files, and the log folder files, can update and change often – and any type of watching/reading/locking interference from outside applications will create issues. The Windows Firewall has also been known to add a latency delay (0.5s) to requests in some circumstances (e.g., if IPv6 is enabled). ## WAMP Layer There are some general Apache, MySQL, and PHP settings that deal with resources that you can increase. But this should only be done on a server that is experiencing increasing loads (otherwise – on a web-dev box, it will just make your system more sluggish)… ### Apache Worker Count ThreadsPerChild is the number of threads Apache will spin up when it starts. Each thread can handle a separate simultaneous client. Generally there would not be a realistic situation (for a typical website and access pattern) where more than 128 workers would be needed for a single server… If all other settings are tuned in, 128 threads can handle about 100 different clients all accessing the server within about a 3 second span. That’s allot of traffic, and a allot of resources. Raising this value overly too much will just make each additional worker/thread take up resources. File Config\Apache\extra\httpd-mpm.conf ThreadsPerChild 96 ThreadLimit 128 If you check Apache’s general error log file and this message is present – "AH00326: Server ran out of threads to serve requests. Consider raising the ThreadsPerChild setting." Then the Apache worker count (ThreadsPerChild) should be raised (but not overly too much as each additional worker/thread will take up resources). Also, if this message is shown – "AH00358: Child: Process exiting because it reached MaxConnectionsPerChild. Signaling the parent to restart a new child process." Then increase value of MaxRequestsPerChild. On the other hand, if this message is not present, decrease the value of MaxRequestsPerChild. This tells Apache when to recycle its workers/threads – to get rid of the memory leaks. Recycling workers/threads once per day is optimal. ### MySQL Cache Size File \Config\Mysql\my.ini # Buffer sizes to 1/4 or 1/2 of your RAM # For MyISAM key_buffer_size = 512MB # For InnoDB innodb_buffer_pool_size = 1000MB # Log size to 1/4 of the above innodb_buffer_pool_size innodb_log_file_size = 256MB The total of these caches and buffers should not exceed 2000MB when using MySQL 32 bit builds as this is about the max usable RAM allocation for a 32 bit process. Changing the value of ‘innodb_log_file_size’ can cause some older versions of MySQL to fail to start, or for the InnoDB Engine to not load. You’ll need to move out (don’t delete just in case) file(s) Database\ib_logfile0 and ib_logfile1 (if it exists). This is a bit unclean, but if everything was flushed and shut down properly, should not be problematic. ### PHP Memory Limit This is generally not a good idea (and will not help scale the website), and only helps when a script needs more memory because it’s bad at managing it (and is crashing PHP)… File \Config\Php\php.ini memory_limit = 1000MB Generally you don’t want set a value above 2000MB (slightly lower than 2GB / 2048MB) when using PHP 32 bit builds as it: 1) Begins to exhaust the memory space PHP can use (running under a 32 bit process). 2) Has been know to trigger PHP bugs. Any script needing more than 1024MB is usually indicative of bad memory management or memory leakage by that script. This is a value PER script. This setting can also be overridden in the VirtualHost, the website’s .htaccess files, and in the script code itself via ini_set('memory_limit', ...). So it’s important to do a quick search to make sure nothing like that is happening. If you check PHP’s general error log file and also the specific website’s PHP error log, and this message is present – "PHP Fatal error: Allowed memory size of xxx bytes exhausted (tried to allocate xxx bytes) in file.php on line xxx." Then PHP’s “memory_limit” value should be increased from the default of 256MB-512MB to somewhere between 512MB-2000MB (* this value cannot be set higher in 32bit PHP versions). ### Enable PHP’s Opcode Cache File \Config\Php\php.ini, Section: [Zend OPcache] Un-comment Zend OPcache section. Save file. Restart Apache. Use PHP’s Zend OPcode to cache PHP scripts as compiled objects. Caching the PHP script files will alleviate some I/O issues, as the scripts will no longer need to be re-read and re-compiled on every request, and they will now exist as objects in memory. It’s usually good for a 50%-200% increase in handling requests/second, decreasing CPU time by 50%, and lowering script execution time… But that is for a typical wordpress website, and comparable to a system that’s currently maxing out (cpu 99%, requests/second peaked, etc)… Your particular case might be a bit different. To exclude certain files from caching add paths to blacklist file: \WampDeveloper\Config\Php\opcache.blacklist.txt ### Disable XDebug File \Config\Php\php.ini, Section: [XDebug] Make sure XDebug is not loaded, as it will slow everything down considerably (at least 2x). ### MySQL Persistent Connections Disable PHP’s MySQL persistent connections. They are never recommended and can cause all kinds of issues as user numbers increase. File \Config\Php\php.ini, Section: [MySQL] ; Allow or prevent persistent links. mysql.allow_persistent=Off ### PHP FCGI Process vs. Apache Module mod_php If Apache is crashing, try switching to PHP-FCGI, which is known to work better with these scale-related bugs and issues. When PHP-FCGI is used, PHP is ran outside of Apache in its own separate process pool. ## True Caching Layer For everything else, there is only one practical way to increase performance of a server that will produce 2x-10x results… Use a caching layer such Apache’s mod_cache to temporarily cache output, or a front-end caching reverse proxy setup (e.g., Varnish or Squid). ## Installing GeoIP Apache Module to Get Country From IP Address Enabling, configuring, and using mod_geoip2 for Apache is very simple… These steps will work for any Windows or Linux Apache installation, but are specific to WampDeveloper Pro (as it already contains mod_geoip2 and its configuration + databases). ## Configuring mod_geoip2 Load WampDeveloper’s mod_geoip configuration by opening file httpd.conf and uncommenting line: Include C:/WampDeveloper/Config/Apache/extra/wampd-geoip.conf WampDeveloper’s included mod_geoip setup contains the following self-explanatory configuration: <IfModule !mod_geoip.c> LoadModule geoip_module modules/mod_geoip.so </IfModule> <IfModule mod_geoip.c> # Enable for all websites and URLs GeoIPEnable On # Turn off mod_geoip token in server signature GeoIPToken Off # Change output charset from ISO-8859-1 (Latin-1) to UTF-8 (for city names only?) GeoIPEnableUTF8 On # Set only the "GEOIP_..." environment variables # Default is: All GeoIPOutput Env # Use true client IP instead of the possibly bogus IP in "Forwarded For" Headers # note - to use IP behind trusted proxy (ex: CloudFlare), use mod_remoteip GeoIPScanProxyHeaders Off # note - If Apache is crashing, instead of GeoIPFlags: MemoryCache or IndexCache, try using: Standard # Load Country level databases into memory (loading into memory will increase httpd proccess size 1.5-2x) GeoIPDBFile C:/WampDeveloper/Tools/GeoIP/GeoIP.dat MemoryCache GeoIPDBFile C:/WampDeveloper/Tools/GeoIP/GeoIPv6.dat MemoryCache # Additional DBs loaded into memory (MemoryCache) can greatly increase httpd process size (2-5x) #GeoIPDBFile C:/WampDeveloper/Tools/GeoIP/GeoLiteCity.dat Standard #GeoIPDBFile C:/WampDeveloper/Tools/GeoIP/GeoLiteCityv6.dat Standard #GeoIPDBFile C:/WampDeveloper/Tools/GeoIP/GeoIPASNum.dat IndexCache #GeoIPDBFile C:/WampDeveloper/Tools/GeoIP/GeoIPASNumv6.dat IndexCache </IfModule> Save changes to the httpd.conf file. Restart Apache. ## Getting Country and Location Data From Client IP Address When enabled, mod_geoip2 provides to Apache and PHP multiple environmental variables containing location specific data of the connecting/client IP address: <?php echo 'Client IP Address: ' . getenv('GEOIP_ADDR'); echo 'Client Country Code: ' . getenv('GEOIP_COUNTRY_CODE'); echo 'Client Country Name: ' . getenv('GEOIP_COUNTRY_NAME'); ?> This data further goes down to the specific city. Output Variables of mod_geoip2 ## Blocking Countries To use GeoIP blocking, set in website’s VirtualHost or .htaccess files the following configuration, updated to include the country-codes that you want to block. GeoIPEnable On # to block China SetEnvIf GEOIP_COUNTRY_CODE CN BlockCountry # to block Russia SetEnvIf GEOIP_COUNTRY_CODE RU BlockCountry # ... place more countries here Deny from env=BlockCountry ## GeoIP Databases GeoLite Legacy Databases are free and can be downloaded from: http://dev.maxmind.com/geoip/legacy/geolite/ GeoLite Legacy Databases are updated on the first Tuesday of each month. WampDeveloper stores the referenced GeoIPDBFile databases in folder C:\WampDeveloper\Tools\GeoIP, and you can use Windows Tasks Scheduler to automatically wget or cURL [both tools are provided] to get updated databases each new month. ## Notes 1. “mod_geoip2″ (v2) is technically version 1.2.x. 2. Use “GeoIP Legacy” .dat databases, not “GeoLite2″ .mmdb databases (they are for mod_maxminddb). 3. mod_geoip module is only provided for Apache 2.4 VC11 32 and 64 bit builds, and Apache 2.2 VC9 32 bit builds. 4. Downloadable mod_geoip builds can be found at ApacheHaus… mod_geoip-1.2.9 (rc): https://www.apachehaus.net/rc/ mod_geoip-1.2.8a: https://www.apachehaus.com/cgi-bin/download.plx 5. Documentation: mod_geoip2 configuration documentation – http://dev.maxmind.com/geoip/legacy/mod_geoip2/ mod_geoip2 changelog – https://github.com/maxmind/geoip-api-mod_geoip2/releases ## Running PHP exec() Shell Functions On WAMP WAMP servers (such as WampDeveloper Pro) usually do not restrict executions of PHP functions – such as exec() and shell_exec(). You can verify this by checking the website’s Apache and PHP error log files. If you are able to run your commands manually from the command-line, but not via WAMP, than the user the Apache Service runs as does not have the needed permissions to execute your commands and binaries (nor interact with the desktop if it is GUI related). If you create a test.php file and place this code inside: <?php echo exec('whoami'); ?> When run via a URL, Apache will output: nt authority\system But if you run “whoami” from the command-line yourself, it will output: <computer-name>\<user-name> The user difference is why those commands do not run via Apache. To execute privileged shell commands via Apache, you’ll have to run “services.msc”, select the Apache service, and change the “Log On” account From “Local System” to another user/account. To avoid permissions issues, create a user in the Administrators group, and make sure to set the user’s password (as password-less accounts are “unauthenticated” which causes further issues). Later on, once you verify that everything is working, you can fine-tune the account’s permissions. And check if what you are trying to execute requires Admin privileges. ## WordPress – Changing the Temp Directory A user was trying to secure different WordPress installations from each other (and the rest of WAMP) by setting each to use a different Temp directory: We currently host 4 different WordPress websites using WAMP. Is it possible to configure the temp directory for each site separately, perhaps as a subdirectory in C:\WampDeveloper\Temp directory? This way a compromised WordPress base will not spread a downloaded payload or script to another base (as normally all PHP scripts share a common Temp folder). Checking the WordPress source-code, WordPress uses this function to find and derive the path of the temporary directory: get_temp_dir() The first thing get_temp_dir() checks for is this PHP runtime constant: WP_TEMP_DIR If you edit the WordPress configuration file wp-config.php, and place this line in, it should set the new temporary folder: define('WP_TEMP_DIR', 'C:\WampDeveloper\Temp\WP1'); The above example is for a sub-directory “WP1″ under the original WampDeveloper Temp directory (on drive C). This sub-directory will need to be created manually. If you use a path outside the \WampDeveloper\Temp directory, note that: 1. You could have issues with Apache not being able to read/write into it (a network share directory, required permissions, etc). 2. Also, PHP’s “open_basedir” setting (it is not enabled by default) would need to be updated in the website’s VirtualHost or .htaccess files to allow the script access to the path (or in php.ini if using PHP-FCGI). If you are using older WordPress plugins that do not use the proper WordPress function get_temp_dir() to get the temp dir, but instead rely on the environmental variables, you can also add a second line into wp-config.php to set env variable TMPDIR: putenv('TMPDIR=' . 'C:\WampDeveloper\Temp\WP1'); ## Laravel – Key size not supported by this algorithm. Only keys of sizes 16, 24 or 32 supported. The new version of PHP 5.6+ is now enforcing proper key sizes. If your Laravel APP_KEY is not the proper (supported) character length, you will get the following error: mcrypt_decrypt(): Key of size 5 not supported by this algorithm. Only keys of sizes 16, 24 or 32 supported. There are 2 ways to fix this: A) “Pad” the key to a valid size. This will preserve your existing encrypted data such as: any data that was saved with Crypt::encrypt() in the database, passwords saved with Hash::make() [note – there is conflicting information on if the key is used during password hashing and storage], and current sessions. B) Or generate a new key and lose your previously encrypted data: php artisan key:generate ## Pad Laravel APP_KEY to Next Supported Length To preserve your existing encrypted data, manually “pad” your existing key to the next valid size (16, 24, 32 characters). This is how invalid size keys were handled internally by the PHP mcrypt_decrypt() function before the change in PHP 5.6+… Previously keys and IVs were padded with ‘\0′ bytes to the next valid size. Example: If it is 10 characters, pad it to 16. If it is 20 characters, pad it to 24. If it is 25 characters, pad it to 32. ### app.php 1. Open your Laravel configuration file: laravel\config\app.php 2. Find line: 'key' => env('APP_KEY', 'SomeRandomString'), The above line attempts to read the value of Laravel’s environmental variable APP_KEY (as defined in Laravel’s .env file), and if unable to do so, uses the quoted value. 3. Count the number of characters the key value is (without the quotes), and make it valid-sized by adding null bytes to the end. You will need to replace the quotes that surround the key value from single quotes to double quotes – so PHP interprets the null bytes correctly. For example, if your key is “12345”, than it is 5 characters long, and it needs to be made 16 characters long like so: "12345\0\0\0\0\0\0\0\0\0\0\0" With the above app.php line like so: 'key' => env('APP_KEY', "12345\0\0\0\0\0\0\0\0\0\0\0"), ### .env The above key value is also stored in Laravel’s .env file (which itself usually acts as the primary source for APP_KEY). 1. Open your Laravel .env file: laravel\.env 2. Find line: APP_KEY=SomeRandomString 3. Update it to the padded value, surrounded by double quotes like so: APP_KEY="12345\0\0\0\0\0\0\0\0\0\0\0" ## Notes As an alternative, you can use the PHP function str_pad to automatically do the above manual padding. For example, to pad a 17-23 character length key to 24: str_pad($str, 24, "\0", STR_PAD_RIGHT);

Also the PHP function chr can be used to return the null byte instead of specifying it with special escape sequences:

chr(0)

Laravel uses PHPDotEnv (3rd-party library) to read the .env file and load the environmental variables. PHPDotEnv uses its own basic text/string format – and you cannot embed PHP code into the .env file. If you are unable to place the null-byte padded value into the .env file, you can comment out (#) the APP_KEY line so Laravel uses the default/fallback value from the app.php file.

The issue is referenced here: mcrypt_decrypt() throws error when PHP 5.6 is used if key is not 32 characters #6722

## Laravel – No supported encrypter found. The cipher or key length are invalid.

A user was trying to install Laravel under WAMP and got the following error:

RuntimeException in compiled.php line 6904: No supported encrypter found. The cipher and / or key length are invalid.

Looking at the Laravel installation instructions, the only WampDeveloper specific change that would need to be done is to load the PHP sockets extension:

1. Open file C:\WampDeveloper\Config\Php\php.ini (via Notepad)

2. Find this line and uncomment it (remove front “;”) –

;extension=php_sockets.dll

3. Save file. Restart Apache.

All the other Laravel required PHP extensions and Apache modules under WampDeveloper are loaded and enabled by default.

The above error seems to be Laravel-specific (rather than having something to do with WAMP) and here is how to fix it…

1. Make sure that in Laravel’s config\app.php file, the 'cipher' is defined as so:

'cipher' => 'AES-256-CBC',

2. Make sure Laravel’s “.env” file exists. If this file does not exist, open the command-line (run cmd.exe), change the command-line’s “working directory” to Lavavel’s installed-to path, and create this file from the provided example template file:

C:
cd \path\to\laravel\folder
copy .env.example .env

The first line (“C:”) changes to drive “C”, the second line changes to the path (on C)… substitute-in for your Laravel installed location. The third line makes a properly-named copy of the base example file. Because this file starts with a period, it’s much simpler to make a copy using the command-line (otherwise you’ll run into issues).

3. The cause of the issue is – the above cipher “AES-256-CBC” needs a 32 character key, but the default random key is only 16 characters long.

Generate a new 32 character string for the key by running (from cmd.exe):

php artisan key:generate
 

The command should automatically update the app.php file (and also the .env file) with a new proper-size key, and output something similar to this afterwards:

Application key [g8MOZ9dYU4ap5F12m95PIPAA5AJG3Sh6] set successfully.

4. Verify that the above key is now in Laravel's .env file:

APP_KEY=g8MOZ9dYU4ap5F12m95PIPAA5AJG3Sh6
 

If it's not, manually add it in as shown above (substitute in your key, and without the brackets).

* On another unrelated but similar cause, if this is happening sometime after a successful installation - after your app is fully installed and running - then it is possible that the APP_KEY was changed and now the encrypted data cannot be decrypted. In this case, unless you can revert to the previous key, you'll have to either delete the encrypted data or start over.