Sending E-Mails fails with no error, except the index.php has a 404. Cannot find any logs, only have smtp.office365.com with STARTTLS

Hello guys,

I have two forms on a website and I am trying to get the first one to work. I have a one-pager-website and the code for the form itself is in a snippet called site/snippets/contact_form.php:

<div class="">
    <div class="relative mx-auto px-1 py-1">
        <div class="">
        <?php if($success): ?>
            <div class="alert success">
                <p><?= $success ?></p>
            </div>
            <?php else: ?>
                <?php if (isset($alert['error'])): ?>
                    <div><?= $alert['error'] ?></div>
                <?php endif ?>
                <form action="<?= $page->url() ?>" method="POST" id="contactform" class="grid grid-cols-1 gap-y-6 sm:grid-cols-2 sm:gap-x-8">
                    <div class="absolute -left-full">
                        <label for="website">Website <abbr title="required">*</abbr></label>
                        <input type="url" id="website" name="website" tabindex="-1">
                    </div>    
                    <div>
                        <div class="mt-1">
                            <input required placeholder="Ihr Name *" type="text" name="name" id="name" value="<?= esc($data['name'] ?? '', 'attr') ?>" autocomplete="name" class="py-3 px-4 block w-full shadow-sm border border-transparent focus:outline-none focus:ring-2 focus:border-mixed-one focus:ring-mixed-one border-gray-300 rounded-sm">
                            <?= isset($alert['name']) ? '<span class="alert error">' . esc($alert['name']) . '</span>' : '' ?>
                        </div>
                    </div>
                    <div>
                        <div class="mt-1">
                            <input required placeholder="Ihre E-Mail-Adresse *" type="email" name="email" id="email" autocomplete="email" class="py-3 px-4 block w-full shadow-sm border border-transparent focus:outline-none focus:ring-2 focus:border-mixed-one focus:ring-mixed-one border-gray-300 rounded-sm" value="<?= esc($data['email'] ?? '', 'attr') ?>">                    
                            <?= isset($alert['email']) ? '<span class="alert error">' . esc($alert['email']) . '</span>' : '' ?>
                        </div>
                    </div>
                    <div class="sm:col-span-2">
                        <div class="mt-1"> <select class="py-3 px-4 block w-full shadow-sm border border-transparent focus:outline-none focus:ring-2 focus:border-mixed-one focus:ring-mixed-one border-gray-300 rounded-sm">
                                <option disabled selected="true">Ich bin ...</option>
                                <option>Option 1</option>
                                <option>Option 2</option>
                                <option>...</option>
                                </select> </div>
                    </div>
                    <div class="sm:col-span-2">
                        <div class="mt-1">
                            <textarea placeholder="Ihre Nachricht" id="message" name="message" rows="4" maxrows="10" class="py-3 px-4 block w-full shadow-sm border border-transparent focus:outline-none focus:ring-2 focus:border-mixed-one focus:ring-mixed-one border-gray-300 rounded-sm">
                                <?= esc($data['message'] ?? '') ?>
                            </textarea>            
                            <?= isset($alert['message']) ? '<span class="alert error">' . esc($alert['message']) . '</span>' : '' ?>

                    </div>
                    </div>
                    <!-- ------------------------- Datenschutz Switch -------------------------- -->
                    <div class="sm:col-span-2">
                        <div class="flex items-start">
                            <div class="flex-shrink-0"> <button type="button" class="relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-mixed-one bg-mixed-one"
                                    x-data="{ on: false }" role="switch" aria-checked="true" :aria-checked="on.toString()" @click="on = !on" x-state:on="Enabled" x-state:off="Not Enabled" :class="{ 'bg-mixed-one': on, 'bg-gray-300': !(on) }">
                    <span class="sr-only">Datenschutz</span>
                    <span aria-hidden="true" class="inline-block h-5 w-5 rounded-full bg-white shadow transform ring-0 transition ease-in-out duration-200 translate-x-5" x-state:on="Enabled" x-state:off="Not Enabled" :class="{ 'translate-x-5': on, 'translate-x-0': !(on) }"></span>
                    </button> </div>
                            <div class="ml-3">
                                <p class="text-base text-gray-500">text text text</p>
                            </div>
                        </div>
                    </div>
                    <!-- ------------------------- Newsletter -------------------------- -->
                    <div class="sm:col-span-2">
                        <div class="flex items-start">
                            <div class="flex-shrink-0"> <button type="button" class="relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-mixed-one bg-mixed-one"
                                    x-data="{ on2: false }" role="switch" aria-checked="true" :aria-checked="on2.toString()" @click="on2 = !on2" x-state:on="Enabled" x-state:off="Not Enabled" :class="{ 'bg-mixed-one': on2, 'bg-gray-300': !(on2) }">
                    <span class="sr-only">Optional: Newsletter</span>
                    <span aria-hidden="true" class="inline-block h-5 w-5 rounded-full bg-white shadow transform ring-0 transition ease-in-out duration-200 translate-x-5" x-state:on="Enabled" x-state:off="Not Enabled" :class="{ 'translate-x-5': on2, 'translate-x-0': !(on2) }"></span>
                    </button> </div>
                            <div class="ml-3">
                                <p class="text-base text-gray-500"> text text text</p>
                            </div>
                        </div>
                    </div>
                    <!-- ---------------------------- ende switches ---------------------------- -->
                    <!-- ------------------------------- captcha ------------------------------- -->
                    <div class="sm:col-span-2">
                        <div class="mt-1">
                            <div>
                                <div class="mt-6 sm:mt-5 space-y-6 sm:space-y-5">
                                    <div class="flex justify-center"> <span class="text-sm text-gray-500" id="title-optional">Spam-Abwehr: Bitte Aufgabe lösen *</span> </div>
                                    <div class="flex justify-center"> <label for="validator" class="submit__control block text-sm font-medium text-gray-700">
                            <span class="text-sm text-gray-500" id="validator"></span>
                            <div class="mt-1 submit__generated"></div>
                            <!-- <i class="fas fa-sync"></i> -->
                            <svg xmlns="http://www.w3.org/2000/svg" class="syncIcon h-10 w-10" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
                            </svg>
                            </label> </div>
                                </div>
                            </div>
                            <div class="gotcha-wrapper"> <input class="w-full px-4 py-4 border" name="gotcha" id="gotcha" value="" placeholder="If you see this invest in better CSS - ignore me" /> </div>
                        </div>
                    </div>
                    <!-- ---------------------------- ende captcha ----------------------------- -->
                    <div class="sm:col-span-2">
                        <button type="submit" name="submit" class="w-full inline-flex items-center justify-center px-6 py-3 border border-transparent rounded-sm shadow-sm text-base font-medium text-white bg-contrast focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-contrast">
                        Nachricht absenden
                        </button> 
                    </div> 
                    <small>* Pflichtfeld</small>
                </form>
            <?php endif ?>
        </div>
    </div>
</div>

The email-validation is copied from the cookbook: site/controllers/contact_form.php:

<?php

return function($kirby, $pages, $page) {

    $alert = null;

    if($kirby->request()->is('POST') && get('submit')) {

        // check the honeypot
        if(empty(get('website')) === false) {
            go($page->url());
            exit;
        }

        $data = [
            'name'  => get('name'),
            'email' => get('email'),
            'message'  => get('message')
        ];

        $rules = [
            'name'  => ['required', 'minLength' => 1],
            'email' => ['required', 'email'],
            'message'  => ['required', 'minLength' => 3, 'maxLength' => 3000],
        ];

        $messages = [
            'name'  => 'Error Name',
            'email' => 'Error Email',
            'message'  => 'Error Message'
        ];

        // some of the data is invalid
        if($invalid = invalid($data, $rules, $messages)) {
            $alert = $invalid;

            // the data is fine, let's send the email
        } else {
            try {
                $kirby->email([
                    'template' => 'email',
                    'from'     => 'info@xxx.com',
                    'replyTo'  => $data['email'],
                    'to'       => 'myemail@gmail.com',
                    'subject'  => esc($data['name']) . ' sent you a message from your contact form',
                    'data'     => [
                        'message'   => esc($data['message']),
                        'sender' => esc($data['name'])
                    ],
                    
                    // new feature that you can try with copy paste here
                    'beforeSend' =>function ($mailer) {
                        $mailer->SMTPOptions = [
                            'ssl' => [
                                'verify_peer' => false,
                                'verify_peer_name' => false,
                                'allow_self_signed' => true
                            ]
                        ];

                        return $mailer;
                    }
                ]);

            } catch (Exception $error) {
                if(option('debug')):
                    $alert['error'] = 'The form could not be sent: <strong>' . $error->getMessage() . '</strong>';
                else:
                    $alert['error'] = 'The form could not be sent!';
                endif;
            }

            // no exception occurred, let's send a success message
            if (empty($alert) === true) {
                $success = 'Ihre Nachricht wurde gesendet. Vielen Dank! Wir werden uns in Kürze bei Ihnen melden.';
                $data = [];
            }
        }
    }

    return [
        'alert'   => $alert,
        'data'    => $data ?? false,
        'success' => $success ?? false
    ];
};

And finally the email config from site/config/config.php:

<?php

return [
  'panel' =>[
    'install' => true
  ],
  'debug' => true,
  'email' => [
    'transport' => [
      'type' => 'smtp',
      'host' => 'smtp.office365.com',
      'port' => 587,
      'security' => 'starttls',
      'auth' => true,
      'username' => 'email',
      'password' => 'password',
    ]
  ],
];

I have nothing found about starttls together with kirby. As far as I know office only supports starttls. Does anybody here has any experience with that?

When I submit the form the page just reloads. Inside the dev-tools in the network-tab I can see that it tries to get the index.php file which always returns a 404 although the file exists. Might that cause an error? I am on nginx with docker.

My files are:

drwxr-xr-x  5 www-data www-data   4096 Aug 27 10:29 assets
-rw-r--r--  1 www-data www-data    900 Aug 27 10:29 composer.json
drwxr-xr-x  9 www-data www-data   4096 Aug 31 18:02 content
-rw-r--r--  1 www-data www-data     67 Aug 27 10:29 index.php
drwxr-xr-x 14 www-data www-data   4096 Aug 27 10:34 kirby
drwxr-xr-x  3 www-data www-data   4096 Sep  2 10:11 media
drwxr-xr-x  2 root     root       4096 Aug 27 10:29 .metals
-rw-r--r--  1 www-data www-data    718 Aug 27 10:29 package.json
-rw-r--r--  1 www-data www-data 177829 Aug 27 10:29 package-lock.json
-rw-r--r--  1 www-data www-data    184 Aug 27 10:29 postcss.config.js
-rw-r--r--  1 www-data www-data    888 Aug 27 10:29 README.md
drwxr-xr-x 11 www-data www-data   4096 Sep  2 12:39 site
-rw-r--r--  1 www-data www-data   2426 Aug 27 10:29 tailwind.config.js

I know that my structure is not perfect yet and that I have some security issues which I will be addressing once the contact-form works.

Thank you any help is appreciated.

What is the name of the template where the form is used, 'home.php? Then your controller has to live in site/controllers/home.php`, otherwise it will not be used at all (There is no such thing as snippet controllers).

Valid values for security are true, tls and ssl.

1 Like

Thank you! I have switched to true and renamed the controller to home.php because indeed my main template is called home.php.

Valid values for security are true , tls and ssl .

So what can I dot when I have STARTTLS given?

I have made the changes but there is no change in the described behavior except for the index.php file is not missing anymore.

Have you tried to set security: 'tls'?

1 Like

Yes. Same result. Where could I get some kind of a logfile? There is nothing produced inside /var/logs/

I have copied the entire example from kirby and it worked. I have seen another support-request in this forum, where some person has added a trailing slash behind the forms action attribute. That helped me as well.

I guess with my php-config I had some wrong rules defined.

But with the copy-pasted example I have new issues: When I submit the form, it will be sent, the page reloads and the line Your message has been sent, thank you. We will get back to you soon! appears. When I reload the same window that message still exists and the e-mail will be sent again! Did anybody else experience this?
I can repeat this for ever. It only goes away if I close the session/the tab. Deleting cache or anything wont solve this.

Another thing would be to scroll to that contact section and not stay at the top but I guess this is handled differently.

Thank you so far for you help!

There are several ways to achieve this, one of which would be to send the sender to a new page on success where you then show the success message.

1 Like

Ok yes but since I am working with a one-page this is not a good idea.

I will work on a solution to not hide the form and still show the success message or something like this. I guess…

Even with a one-pages you will most likely have other pages like an imprint and privacy pages?

But you could also unset the data on success so there is nothing to send anymore and/or disable the form.

1 Like