nliautaud / p01contact

Create contact forms by writing simple tags. Also a plugin for GetSimple and Pico CMS.
MIT License
16 stars 15 forks source link

Emails not being received #41

Closed beejay41 closed 5 years ago

beejay41 commented 5 years ago

Hi Nicolas, Just trying to upgrade from version 0.9.1 and came back to an old issue. Your plugin 1.1.4 is working as intended, CPanel Track Delivery even shows the email was delivered to the intended server, and yet it never arrives in my inbox. The problem, I believe, is that the email is sent with the visitors email address, something which will be rejected by SPF validation these days. Looking back, I realise I patched 0.9.1 send_mail() to always use GSFROMEMAIL as the sending address (also calling ini_set("sendmail_from", GSFROMEMAIL) required by some hosts, I found). This solved the problem, provided the SPF record includes the hosting server. I must apologise for not reporting this solution way back on issue #12 . I haven't quite worked out how to apply this to 1.1.4 properly. I'd likely patch P01contactForm::mailHeaders() as above. The main side effect, is that "Reply" won't work in your email client, however "Reply-All" usually does, at least in the clients I've tried.

Regards, Brian

nliautaud commented 5 years ago

Ouh, interesting. I'd love to see some docs on the subject if you have that. PR welcome, along with a setup for testing.

beejay41 commented 5 years ago

Hi Nicolas, I’m not an expert on SPF, but Wikipedia gives the idea of what it does: https://en.wikipedia.org/wiki/Sender_Policy_Framework

I’ve used Google and Zoho mail systems, which used to provide free 25 user accounts using your own domain name and both recommend setting up SPF records. My own ISP, Virgin Media UK, appear to use SPF, but just drops failing email without logs or warning. Fortunately, Zoho.com allows you to quarantine failing emails and examine the delivery failure.

I found the “ini_set” necessary on one particular hosting account, to satisfy the provider’s rules. I don’t know how necessary it is generally, but causes no problem on other hosting providers I’ve used. This pre-dates the SPF issue and prevented any sending, but didn’t cause send() to fail. It may passible be set automatically by CPanel these days.

To test, you need a receiving mail server correctly configured to use SPF checking. Last I looked, Zoho.com still provided single user accounts using your own domain. You can get a free domain name from freenom.com, for example, to use with this. You also need GS site for this domain, with your contact page.

I will do a crude patch and let you know the outcome. Regards, Brian

beejay41 commented 5 years ago

With the following patch, email was delivered as expected:

    private function mailHeaders($name, $email, $mime_boundary)
    {
        $encoded_name = $this->encodeHeader($name);
        $headers  = "From: $encoded_name".' <'.GSFROMEMAIL.">\n";
        if ($email) {
//            $headers .= " <$email>\n";
            $headers .= "Reply-To: $encoded_name <$email>\n";
            $headers .= "Return-Path: $encoded_name <$email>";
        }
        $headers .= "\n";
        $headers .= "MIME-Version: 1.0\n";
        $headers .= "Content-type: multipart/alternative; boundary=\"$mime_boundary\"\n";
        $headers .= "X-Mailer: PHP/" . phpversion() . "\n";
        return $headers;
    }

The ini_set() described, was not required for this host and adding it made no difference. Needs documentation that GSFROMEMAIL should to be set to an email at your domain. Would be best to test GSFROMEMAIL is set and perhaps use recipient as fallback or abort. Hope this helps, Brian

nliautaud commented 5 years ago

Thanks.

Would like to try first a non GS-only or cms-specific way to do it, and that wouldn't require manually setting an address. It has been a while since I looked at those, but for example would something like that pass SPF ?

        $headers  = "From: $encoded_name <no-reply@" . SERVERNAME . ">\n";
        if ($email) {
            $headers .= "Reply-To: $encoded_name <$email>\n";
            $headers .= "Return-Path: $encoded_name <$email>";
        }
beejay41 commented 5 years ago

For me, that gives the same result. Thanks.

nliautaud commented 5 years ago

Great thanks for the follow-up, I'll implement that soon.