Welcome Guest, Not a member yet? Register   Sign In
How To: Shield - Send Email to user on Admin Created User
#1
Information 
(This post was last modified: 05-24-2023, 05:26 AM by DeanE10. Edit Reason: removed unneeded areas of text and code )

Stack Response reposted here

This will cover how to send an email to a newly registered user using an Admin panel outside of Shields default Self Registration. The idea here is to maintain Shields default file system incase there is an update. We don't want to lose our work if we perform an update and it overwrites one of the files we modified. An additional use case would be based on the need to turn of Self Registration IE: $allowRegistration = false;

FIRST: Make sure you have completed the setup - Composer will be your best option
**************** 
1. [Installation Link]
2. [Setup Link]
**************** 

Once you are all setup and verified Shield is working properly, you can add an Authentication Action to perform the email task.  Additional information on Authentication Actions can be found [here]. This will allow you to configure more if needed and defines the two provided by Shield (EmailActivate, Email2FA).
 
Ok, Let's get to work! 

app/Config/Events.php
We need to add an event to send the new user an email

PHP Code:
....
use 
CodeIgniter\I18n\Time;
use 
CodeIgniter\Shield\Exceptions\LogicException;
use 
CodeIgniter\Shield\Exceptions\RuntimeException;

// notice I am passing two variables from the controller $user and $tmpPass
// I will force the user to change password on first login
Events::on('newRegistration', static function ($user$tmpPass) {

    $userEmail $user->email;
    if ($userEmail === null) {
        throw new LogicException(
            'Email Activation needs user email address. user_id: ' $user->id
        
);
    }

    $date      Time::now()->toDateTimeString();

    // Send the email
    $email emailer()->setFrom(setting('Email.fromEmail'), setting('Email.fromName') ?? '');
    $email->setTo($userEmail);
    $email->setSubject(lang('Auth.emailActivateSubject'));
    $email->setMessage(view(setting('Auth.views')['email_manual_activate_email'], ['userEmail' => $userEmail,'tmpPass' => $tmpPass'date' => $date]));

    if ($email->send(false) === false) {
        throw new RuntimeException('Cannot send email for user: ' $user->email "\n" $email->printDebugger(['headers']));
    }

    // Clear the email
    $email->clear();

}); 

app/Controllers/Users.php

PHP Code:
....
use \
CodeIgniter\Events\Events;
use \
CodeIgniter\Config\Factories;

// modify however you want. I use Ajax...
    public function add() {

        checkAjax();

        if (!$this->user->hasPermission('users.create')) {
            $response['success']       false;
            $response['messages']      lang("App.invalid_permission");
            return $this->response->setJSON($response);
        }

        $response = array();

        $fields['username']         $this->request->getPost('username');
        $fields['password']         $this->request->getPost('password');
        $fields['email']            $this->request->getPost('email');
        $fields['group']            $this->request->getPost('group');

        $this->validation->setRules([
            'username'              => ['label' => 'Username''rules'          => 'required|max_length[30]|min_length[3]|regex_match[/\A[a-zA-Z0-9\.]+\z/]|is_unique[users.username,id,{id}]'],
            'password'              => ['label' => 'Password''rules'          => 'required|min_length[8]'],
            'email'                 => ['label' => 'Email Address''rules'     => 'required|valid_email|is_unique[auth_identities.secret,id,{id}]'],
            'group'                 => ['label' => 'Group''rules'             => 'required'],
        ]);

        if ($this->validation->run($fields) == FALSE) {

            $response['success']    false;
            $response['messages']   $this->validation->getErrors(); //Show Error in Input Form
        } else {

            $users                         auth()->getProvider();
            $user                          = new User([
                'username'                 => $fields['username'],
                'email'                    => $fields['email'],
                'password'                 => $fields['password'],
                'status_message'           => 'New User',
            ]);
            // save the user with the above information
            $users->save($user);
            // get the new ID as we still have work to do
            $user                          $users->findById($users->getInsertID());
            // set the flag to make user change password on first login
            $user->forcePasswordReset();
            // make sure this is the only group(s) for the user
            $user->syncGroups($fields['group']);

            // Additional work done here..
            $actionClass                   setting('Auth.actions')['register'] ?? null;
            $action                        Factories::actions($actionClass)->createIdentity($user);
            $code                          $action// do not need this but want to set it anyway
            $tmpPass                       $fields['password'];
            // trigger our new Event and send the two variables 
            $confirm                       Events::trigger('newRegistration'$user$tmpPass);

            // if everything went well, notify the Admin the user has been added and email has been sent
            if ($confirm) {
                $response['success']       true;
                $response['messages']      lang("App.insert-success");
            } else {
                $response['success']       false;
                $response['messages']      lang("App.insert-error");
            }
        }
        return $this->response->setJSON($response);
    

email template -> CodeIgniter\Shield\Views\Email\email_manual_activate_email
This is a very slightly modified version of the Shield's default file (action_email_activate_email). Was thinking it might better to put in a Majic-Link... Maybe later...

PHP Code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<
head>
    <meta name="x-apple-disable-message-reformatting">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="format-detection" content="telephone=no, date=no, address=no, email=no">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title><?= lang('Auth.emailActivateSubject'?></title>
</head>
<body>
    <p><?= lang('App.emailActivateMail'?></p>
    <div style="text-align: center">
        <h3><?= site_url(); ?></h3>
        <p>User ID: <?= $userEmail?></p>
        <p>Temporary Password: <?= $tmpPass?></p>
    </div>
    <table role="presentation" border="0" cellpadding="0" cellspacing="0" style="width: 100%;" width="100%">
        <tbody>
            <tr>
                <td style="line-height: 20px; font-size: 20px; width: 100%; height: 20px; margin: 0;" align="left" width="100%" height="20">
                     
                </td>
            </tr>
        </tbody>
    </table>
    <b><?= lang('Auth.emailInfo'?></b>
    <p><?= lang('Auth.emailDate'?> <?= esc($date?><br>
    Email System Generated for a New User.</p>
</body>
</html> 

Make sure you add this line in app/Config/Auth.php

PHP Code:
public array $views = [
              'email_manual_activate_email' => '\CodeIgniter\Shield\Views\Email\email_manual_activate_email',
    ]; 

Now your new users will receive an email when you set them up, even if

PHP Code:
$allowRegistration false

Once they login for the first time, it will also send them a new code. Verifying the code will send them to wherever you have the force_reset redirect set to. I set this forcing the user to their Profile with a SweetAlert (again, I use lots of Ajax) to let them know they need to change their password. Plus, this is a great opportunity for them to enter all of their personal information as well.

PHP Code:
    public array $redirects = [
        'register'    => '/',
        'login'       => '/',
        'logout'      => '/login',
        'force_reset' => '/profile',
    ]; 

With the personal or extra data I mention above that you need to enter into the DB for the user, you can either expand the users table, or create a new table.  More information on that [here with code] to assist.

Hope this helps!
If you see a mistake or if your way is better, post it below!

- Dean
Reply
#2

CodeIgniter\Shield\Exceptions\RuntimeException

Cannot send email for user:
I use default setup, why still unable to actvate/send the email,
I wonder why
Reply
#3

(08-21-2023, 04:59 PM)yamin88 Wrote: CodeIgniter\Shield\Exceptions\RuntimeException

Cannot send email for user:
I use default setup, why still unable to actvate/send the email,
I wonder why

Make sure you have done the email settings in file app/Config/Email.php. Please refer to the description below.

https://codeigniter4.github.io/shield/in...mand-setup
Reply




Theme © iAndrew 2016 - Forum software by © MyBB