PHPMailer is the most widely used PHP library for sending email, and it is a good fit for contact forms: it builds correct headers, handles HTML and attachments, and reports errors clearly. On shared hosting, though, how PHPMailer sends matters more than how you install it. This short guide shows the setup that works on Domain India shared hosting today.
On Domain India cPanel hosting, PHPMailer's SMTP mode fails because the socket functions it needs are disabled, and its mail mode silently drops your envelope sender. The reliable pattern is to let PHPMailer build the message, then send it yourself with PHP mail() and -f set to an address on your own domain. Always send from your own domain, put the visitor's address in Reply-To, and publish SPF, DKIM and DMARC records.
This article covers PHPMailer for contact forms. For the complete picture (the envelope sender, SPF, DKIM and DMARC, testing, frameworks and WordPress), read PHP sendmail settings and sending email from PHP.
1. Why the usual PHPMailer examples fail on shared hosting
Most PHPMailer tutorials use SMTP: isSMTP(), a host, a port and a mailbox password. On our cPanel servers that route does not work from PHP. Shared hosting disables a set of PHP functions for security. On cPanel they include the socket functions fsockopen and stream_socket_client that SMTP needs; on both cPanel and DirectAdmin they include the process functions (proc_open, popen) that a sendmail transport needs. When SMTP is blocked, the error looks like this:
stream_socket_client() has been disabled for security reasonsPHPMailer's mail mode (isMail()) does send, because it uses PHP's mail(). But PHPMailer passes your envelope sender (-f) only when the PHP function escapeshellcmd is available, and that function is disabled on our cPanel servers. Without -f, the Return-Path becomes the server's own address, SPF is checked against the server instead of your domain, and your messages are more likely to land in spam.
For the full list and the reasons behind it, see PHP disabled functions on shared hosting.
2. Install PHPMailer
Composer cannot run on shared hosting, so install PHPMailer on your own computer and upload it:
- Install on your computer.In your project folder run
composer require phpmailer/phpmailer. This creates avendor/folder. - Upload the project.Upload the project, including
vendor/, with FTP or the File Manager. Keep it outsidepublic_htmlif you can, and put only your form handler inpublic_html. - Or download manually.Without Composer, download the release from the PHPMailer GitHub page and upload its
srcfolder. ThenrequireException.phpandPHPMailer.phpdirectly instead ofvendor/autoload.php.
Before you write the code, create a real mailbox to send from, such as [email protected], in your control panel.
3. A contact form handler that works on shared hosting
PHPMailer builds the message; PHP mail() sends it with your envelope sender:
<?php
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
require __DIR__ . '/../vendor/autoload.php'; // adjust to where vendor/ is
$from = '[email protected]'; // a mailbox on YOUR domain
$to = '[email protected]'; // where enquiries should arrive
$name = trim($_POST['name'] ?? '');
$visitor = trim($_POST['email'] ?? '');
$message = trim($_POST['message'] ?? '');
if (!filter_var($visitor, FILTER_VALIDATE_EMAIL) || preg_match('/[\r\n]/', $name) || $message === '') {
http_response_code(400);
exit('Please fill in all fields with a valid email address.');
}
$mail = new PHPMailer(true);
try {
$mail->isMail();
$mail->CharSet = 'UTF-8';
$mail->setFrom($from, 'Your Business');
$mail->addAddress($to);
$mail->addReplyTo($visitor, $name); // the visitor goes in Reply-To
$mail->Subject = 'Website enquiry from ' . $name;
$mail->Body = "Name: $name\nEmail: $visitor\n\n$message\n";
$mail->preSend(); // build the message, don't send
// Split the built message into headers and body.
[$head, $body] = preg_split("/\r?\n\r?\n/", $mail->getSentMIMEMessage(), 2);
$head = preg_replace("/\r?\n[ \t]+/", ' ', $head); // unfold long headers
$headers = [];
$subject = '';
foreach (preg_split("/\r?\n/", $head) as $line) {
if (stripos($line, 'To:') === 0) { continue; } // mail() adds To
if (stripos($line, 'Subject:') === 0) { $subject = trim(substr($line, 8)); continue; }
$headers[] = $line;
}
$ok = mail($to, $subject, $body, implode("\r\n", $headers), '-f' . $from);
echo $ok ? 'Thank you, your message has been sent.' : 'Sorry, the message could not be sent.';
} catch (Exception $e) {
error_log('Contact form error: ' . $mail->ErrorInfo);
echo 'Sorry, the message could not be sent.';
}Notes on this handler:
- The
-fvalue is a fixed address you control. Never build it from form input. - The visitor's address goes only in Reply-To. Putting it in From makes the message fail SPF and DMARC.
- For attachments or HTML, add
addAttachment(),isHTML(true)andAltBodybeforepreSend(). The same split-and-send code handles them. - If
mail()alone is enough (plain-text enquiries, no attachments), the shorter handler in the full guide does the same job without PHPMailer.
4. Protect the form from abuse
An unprotected contact form is quickly found by spam bots, and every message it sends counts towards your account's sending limit (200 messages per hour per account on cPanel, 1,000 per day on DirectAdmin).
- Validate every field on the server, as the example does.
- Add a CAPTCHA or a hidden honeypot field.
- Send enquiries only to your own fixed address, never to an address typed into the form.
5. Check that it works
Send a test enquiry to a Gmail address you own, open the message and choose Show original. SPF, DKIM and DMARC should show PASS, and the Return-Path should be your own address. If SPF or DKIM fails, set up the records described in the full guide.
6. Other ways to send
- An HTTPS email API. Transactional providers accept email over HTTPS. On cPanel, a single cURL request (
curl_exec) works, but client libraries that rely oncurl_multi_execor sockets may fail. On most DirectAdmin sitescurl_execis disabled too, whileallow_url_fopenis on, sofile_get_contents()with an HTTPS stream context is the route there. Test before you rely on either. - A VPS or the App Platform. On a server you control, or on the App Platform, PHPMailer's SMTP mode works normally and can send through any authenticated mailbox.
Why does PHPMailer SMTP fail on shared hosting?
SMTP needs PHP socket functions such as fsockopen and stream_socket_client, which are disabled on Domain India cPanel hosting for security. Use PHPMailer to build the message and send it with PHP mail() and the -f envelope sender, or send through an HTTPS email API.
Why does my PHPMailer email go to spam when using isMail()?
PHPMailer only passes the -f envelope sender when escapeshellcmd is available, and it is disabled on our cPanel servers. Without -f the Return-Path is the server's address, so SPF does not align with your domain. Call mail() yourself with -f, as in the handler above, and publish SPF, DKIM and DMARC.
Can I install PHPMailer with Composer on shared hosting?
Composer cannot run on shared hosting. Run composer require phpmailer/phpmailer on your own computer and upload the project with its vendor folder, or download PHPMailer from GitHub and upload its src folder.
Which From address should a contact form use?
A mailbox on your own domain, such as [email protected]. Put the visitor's email address in Reply-To so that replying still reaches them.
How many emails can my contact form send?
Every message counts towards your hosting account's limit: 200 messages per hour per account on cPanel and 1,000 per day on DirectAdmin. Protect the form with a CAPTCHA or honeypot so bots can't use it up.
Ready to put a working contact form on your site? Compare cPanel hosting and DirectAdmin hosting, or open a support ticket if your form still won't send.
Email accounts on your own domain, PHP mail() that works on every shared plan, and support that will check your mail setup with you.
See hosting plans