Contact Form Error: Undefined variable $name

Hi,

I followed the contact form example from the cookbook on the website.

When I send the form to the plaintext template, it returns an error saying, “Undefined variable $name.”

I took the $name out of the email template and it returned an error saying “undefined variable $email,” which makes me think the form is not passing the values from the form to the template.

I read through the sending emails from Kirby directions, but didn’t understand how or if that applies.

What could I try next for troubleshooting?

To help people help you, I suggest you:

  • link to the cookbook example you’re referencing;
  • show your code.

Do you create any array of PHP data in your contact form controller, and if yes does this data structure correspond to the variable names you’re trying to access in your templates or is there a mismatch?

If the example you followed is Cookbook: Contact form, the code samples there are returning an array with a 'data' key in the controller, and using $data['name'] and $data['email'] in the templates. If you changed the templates to use $name and $email instead, but didn’t change the controller, that would be a mismatch and could explain your errors.

Hi, thank you for your reply. Yes, I am using the Cookbook contact form.

Here’s my…

contact.php template:

 <?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 method="post" action="<?= $page->url() ?>">
            <div class="honeypot">
                <label for="website">Website <abbr title="required">*</abbr></label>
                <input type="url" id="website" name="website" tabindex="-1">
            </div>
            <div class="field">
                <label for="name">
                    Name <abbr title="required">*</abbr>
                </label>
                <input type="text" id="name" name="name" value="<?= esc($data['name'] ?? '', 'attr') ?>" required>
                <?= isset($alert['name']) ? '<span class="alert error">' . esc($alert['name']) . '</span>' : '' ?>
            </div>
            <div class="field">
                <label for="email">
                    Email <abbr title="required">*</abbr>
                </label>
                <input type="email" id="email" name="email" value="<?= esc($data['email'] ?? '', 'attr') ?>" required>
                <?= isset($alert['email']) ? '<span class="alert error">' . esc($alert['email']) . '</span>' : '' ?>
            </div>
            <div class="field">
                <label for="text">
                    Text <abbr title="required">*</abbr>
                </label>
                <textarea id="text" name="text" required>
                    <?= esc($data['text'] ?? '') ?>
                </textarea>
                <?= isset($alert['text']) ? '<span class="alert error">' . esc($alert['text']) . '</span>' : '' ?>
            </div>
            <input type="submit" name="submit" value="Submit">
        </form>
        <?php endif ?>

The contact.php controller (my domain replaces “mysite”)

<?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'),
            'text'  => get('text')
        ];

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

        $messages = [
            'name'  => 'Please enter a valid name',
            'email' => 'Please enter a valid email address',
            'text'  => 'Please enter a text between 3 and 3000 characters'
        ];

        // 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'     => 'yourcontactform@mysite.com',
                    'replyTo'  => $data['email'],
                    'to'       => 'hello@mysite.com',
                    'subject'  => esc($data['name']) . ' sent you a message from your contact form',
                    'data'     => [
                        'text'   => esc($data['text']),
                        'sender' => esc($data['name'])
                    ]
                ]);

            } 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 = 'Your message has been sent, thank you. We will get back to you soon!';
                $data = [];
            }
        }
    }

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

and my email.php template


<?= $name ?>

<?= $email ?>

<?= $text ?>

Thank you!

This is where you ask Kirby to render the email.php template. The 'data' array contains what PHP variables will be set in that template:

Because you’re passing an array with two keys, 'text' and 'sender', the defined variables in the email template will be $text and $sender. No $email or $name.

You need to also pass 'email' and 'name' keys with the correct value in that array; or alternatively just do 'data' => $data to pass the whole $data array.

Thank you, that’s helpful.

Now the error says it cannot connect to the SMTP host.

I am searching for forum for posts about configuring sendmail now…

I pointed the SMTP to icloud.

Here is the code from my config.php


   'email' => [
      'from' => 'name@domain.com', 
      'name' => 'My Name',
      'replyTo' => 'name@domain.com', 
      'send' => [
         'driver' => 'smtp', 
         'host' => 'smtp.mail.me.com', 
         'port' => 587,
         'username' => 'name@doman.com', // my full iCloud email address
         'password' => 'xxx', // my iCloud App-Specific Password
         'secure' => 'tls', 
      ],
   ],

Now Kirby says the form was sent, but nothing arrives in the mail.

I verified my credentials are accurate, and am not sure what to do next.

Thanks in advance for any suggestions.

Where did you get this config structure from?

Doesn’t quite look like the one documented: email | Kirby CMS

Hmm, debugging what SMTP servers do is probably outside the scope of this forum.

My general guess would be that it’s uncommon to use an email service meant for individual users and to use that as the email sender for a website or other automated service. Generally the email service providers who offer a service to individuals have terms and conditions that forbid that, or may rate-limit sending emails, or may filter out emails that seem to come from servers rather than email client software.

And if the emails do go through, if a website ends up sending many emails via the same user account, that account (here an iCloud account) might get classified as a spammer by other emails services (like Google Mail). So it can be dangerous to do it that way.

As a result, most websites use some “email delivery service” like SendGrid, Postmark and others to send their transactional emails. These delivery services provide SMTP servers and APIs for sending emails, debugging tools, and try to work with (or work around) the big email providers like GMail, Yahoo, Outlook and iCloud to avoid going straight to spam.

Thank you both for your help.

I got that code from this post: Cookbook contact form and PHP Mailer

My host, you, and others on this forum do not recommend using PHP to send mail, so I gave up on using the form through Kirby.

But you missed the transport key, ending up with the wrong syntax

Exactly, it should be transport not send. It’s also not 'driver' => 'smtp' but 'type' => 'smtp' That’s why I was asking, I though maybe this was provided by an AI chatbot as it looks close to the right thing, but not really (in the post you linked they are mentioned correctly).

Thanks again. I’ve been working on this for days and am burnt out, but will try a little more. I’ve obviously mixed up my code sources. :tired_face:

Hi,

Thanks for your patience if you are reading this.

I went back to the contact cookbook and copied the contact.php template at /site/templates/contact.php:

            <?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 method="post" action="<?= $page->url() ?>">
            <div class="honeypot">
                <label for="website">Website <abbr title="required">*</abbr></label>
                <input type="url" id="website" name="website" tabindex="-1">
            </div>
            <div class="field">
                <label for="name">
                    Name <abbr title="required">*</abbr>
                </label>
                <input type="text" id="name" name="name" value="<?= esc($data['name'] ?? '', 'attr') ?>" required>
                <?= isset($alert['name']) ? '<span class="alert error">' . esc($alert['name']) . '</span>' : '' ?>
            </div>
            <div class="field">
                <label for="email">
                    Email <abbr title="required">*</abbr>
                </label>
                <input type="email" id="email" name="email" value="<?= esc($data['email'] ?? '', 'attr') ?>" required>
                <?= isset($alert['email']) ? '<span class="alert error">' . esc($alert['email']) . '</span>' : '' ?>
            </div>
            <div class="field">
                <label for="text">
                    Text <abbr title="required">*</abbr>
                </label>
                <textarea id="text" name="text" required>
                    <?= esc($data['text'] ?? '') ?>
                </textarea>
                <?= isset($alert['text']) ? '<span class="alert error">' . esc($alert['text']) . '</span>' : '' ?>
            </div>
            <input type="submit" name="submit" value="Submit">
        </form>
        <?php endif ?>

I copied the contact.php controller at /site/controllers/contact.php, and used my own email address:

<?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'),
            'text'  => get('text')
        ];

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

        $messages = [
            'name'  => 'Please enter a valid name',
            'email' => 'Please enter a valid email address',
            'text'  => 'Please enter a text between 3 and 3000 characters'
        ];

        // 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'     => 'email@mydomain.com',
                    'replyTo'  => $data['email'],
                    'to'       => 'email@mydomain.com',
                    'subject'  => esc($data['name']) . ' sent you a message from your contact form',
                    'data'     => [
                        'text'   => esc($data['text']),
                        'sender' => esc($data['name'])
                    ]
                ]);

            } 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 = 'Your message has been sent, thank you. We will get back to you soon!';
                $data = [];
            }
        }
    }

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

I removed any email transport code from the config.php, because I think that will make Kirby default to Sendmail (if I understand that correctly).

I used the following code (from the cookbook) for my email template at /site/templates/emails/email.php:

Hello Company,

<?= $text ?>

<?= $sender ?>

When I submit the form, Kirby says it was sent. However, nothing comes into my inbox.

Should this work? What am I missing technically and/or conceptually?

I suspect that if you don’t provide a configuration for sending emails through a custom SMTP server, Kirby just calls PHP’s mail() function, which passes the email to the operating system’s default email sending service, which itself may not be connected to anything. If the operating system doesn’t outright reject the email, from PHP’s point of view there may be no error, but the email might never get sent.

If you’re testing locally, chances are that calling mail() will not work at all. And if you’re testing on your web host’s server, it depends on how their configured the operating system—you should check their documentation.

The PHP docs for the mail() function has a bunch of warnings about delivery:

Returns true if the mail was successfully accepted for delivery, false otherwise.

It is important to note that just because the mail was accepted for delivery, it does NOT mean the mail will actually reach the intended destination.

(source, and here too)

For local testing, I’d recommend a tool like MailPit or MailHog, we have a recipe for MailHog here: Email testing | Kirby CMS .

For production, I’d recommend a service provider, as already suggested above.

Thank you fvsch and texnixe.