Does anyone have group emails working for users?

Iā€™ve been combing through old posts all day on this topic, reviewing the code and the database tables trying to figure out whatā€™s going on without any luck (or direction to go in!). Thought it might be a good idea to start a new thread rather than bump a bunch of old ones.

I can add group email accounts, I can see them as administrator but canā€™t assign them to users properly or have the users be able to see the group inbox folders.

Does anyone have this working? If so, please help! Iā€™ve seen all the existing threads and also the bug report on Github. Kind of looking for something new if anyone has insight.

Hereā€™s what Iā€™ve found so farā€¦

I can confirm there is still an issue here. 7.12.8. Iā€™ve done a bunch of testing as well. What Iā€™ve found so farā€¦

  1. My folders_subscription is getting populated properly in the DB
  2. An older group email that I added has no issues.
  3. A recent group email I canā€™t have users see it. (Admin works no problem).
  4. I can add the folder subscriptions by logging in as admin to the user. (However, the popup says ā€œsavedā€ but they are never saved, if I re-open the user, they are gone).
  5. The folder subscriptions are not available for the user when logged in as the user!!!

Iā€™ve added a video here demonstrating whatā€™s happening.

Iā€™ve tried the usual stuff like file permissions/ownership and examining the folder_subscription table in the Database (which looks like itā€™s properly associating the folder with the user.

The only errors I get are about duplicate folders being detected. Iā€™ve checked, there are no duplicate folders. I think when I save, itā€™s trying to re-add the folders that are already in the table, and thus the error. Which I donā€™t think is a problem, because the folder ARE in the table.

2 Likes

I found this screen shot from SugarCRM from 9 years ago. Wondering if its from CE? It appears some functionality is missing in SuiteCRM that was there to select the team the group email was assigned to.

Anyone know the history on this and how we got to where we are now?

ā€œTeamsā€ were SugarCRM Pro features, if Iā€™m not mistaken.

I think that Group Emails should work in SuiteCRM, though these configurations are always a bit fragile. I would recommend trying things out with a really simple email account, nothing Gmail or Hotmail or Azure, nothing OAuth or whatever. Just plain user/password account. I use gmx.com emails for all my tests.

Another thing that you might want to check is how things are saved in the DB. Double-check everything in inbound_email, outbound_email, including the fields that are Base64 encoded.

Finally, you can step through the inbound email process with a debugger to see exactly how/why itā€™s failing to get the email. Start here: https://github.com/salesagility/SuiteCRM/blob/master/modules/Schedulers/_AddJobsHere.php#L560

(you want function pollMonitoredInboxesAOP, donā€™t confuse it with pollMonitoredInboxes which is the old version)

Thanks for pointing me in the right direction @pgr Iā€™ll have a look at that file.

Iā€™m using just a standard imap email from cpanel. It works no problem if Iā€™m signed in as admin, itā€™s only when signed in as a user that doesnā€™t work. Iā€™ve checked all the database tables and they appear to have the correct associations. This blog article on how the email folders work was super helpful in understanding it.

Angel's Blog: SugarCRM In-Depth: E-mail Folders

One other bug Iā€™ve found while troubleshooting this is that if Admin creates the ā€œpersonalā€ inbound or outbound email account for a user, itā€™s not available for the user either. This I solved because the ā€œassigned userā€ of the email account ends up being admin and then the user doesnā€™t have access. By changing it to the user in the DB solves this issue, and this is what happens when the user creates their own email account. However, this is not the same thing going on with group emails. Itā€™s super puzzling because it seems itā€™s making the correct entries in the DB for it to work. Iā€™m suspecting it might be a security group or role issue thatā€™s preventing the inboxes from showing. However, I canā€™t find a way to associate the inbound email account with a security group or role.

OK, some progressā€¦ at least a direction. If Iā€™m logged in as the user and construct the url like this:

/index.php?module=Emails&action=index&folders_id=3ddc71c1-5488-bee6-06a1-645a6cf455ed

Where the id is the folder ID of the inbox, the user can see the inbox! So the issue (I think?) is with the email account switcher in the email module. For whatever reason, it doesnā€™t show the group email inbox as an option. However, the user clearly has access to it!

Ok need a little help here. Iā€™m so close to fixing the group emails problem (I think!!!). I found exactly where the problem is, actually there are a few problems.

  1. in the folders table ā€œis_groupā€ is not getting populated. Thatā€™s a problem for another day, I just manually changed to ā€œ1ā€ for now.

  2. There is an error in the code ā€œisgroupā€ should be ā€œis_groupā€. I fixed that. Easy. Now the real problemā€¦

  3. In SugarFolders.php in the function retrieveFoldersForProcessingā€¦

There is a filter I guess to filter out non group folders. In fact, if I change it up to not equal to one, I can see all folders as a user. I think we want the condition to be only IF, itā€™s the account created by the user OR if itā€™s a group account. However, the condition for ā€œis_groupā€ never returns true. My php skills to deal with arrays of arrays are not that great. Please help if you can!!! Here is the filter as well as the output (example) from the $return array:

FILTER:

$secureReturn = [];

        foreach ($return as $item) {
            if ($item->is_group === 1 || $item['created_by'] === $user->id || is_admin($user)) {
                $secureReturn[] = $item;
            }
        }

        return $secureReturn;

For non-admin users, this always returns false and no mailboxes, except the personal email is returned.

HERE IS THE $RETURN Array:

(
    [id] => 3ddc71c1-5488-bee6-06a1-645a6cf455ed
    [name] => INBOX (Reply)
    [has_child] => 1
    [is_group] => 1
    [is_dynamic] => 1
    [dynamic_query] => 
    [folder_type] => inbound
    [created_by] => 1
    [deleted] => 0
    [children] => Array
        (
            [0] => Array
                (
                    [id] => 4523a166-b4de-c2b4-41ed-645a6c90db8d
                    [name] => Drafts (INBOX.Sent)
                    [folder_type] => draft
                    [parent_folder] => 3ddc71c1-5488-bee6-06a1-645a6cf455ed
                    [has_child] => 0
                    [is_group] => 1
                    [is_dynamic] => 1
                    [dynamic_query] => 
                    [assign_to_id] => 
                    [created_by] => 1
                    [modified_by] => 1
                    [deleted] => 0
                )

            [1] => Array
                (
                    [id] => 4579d172-d34f-40ca-646f-645a6cf43e64
                    [name] => Sent Emails (INBOX.Sent)
                    [folder_type] => sent
                    [parent_folder] => 3ddc71c1-5488-bee6-06a1-645a6cf455ed
                    [has_child] => 0
                    [is_group] => 1
                    [is_dynamic] => 1
                    [dynamic_query] => 
                    [assign_to_id] => 
                    [created_by] => 1
                    [modified_by] => 1
                    [deleted] => 0
                )

            [2] => Array
                (
                    [id] => 459bb6bb-fb67-fb7b-4bc8-645a6cd4246f
                    [name] => Archived Emails
                    [folder_type] => archived
                    [parent_folder] => 3ddc71c1-5488-bee6-06a1-645a6cf455ed
                    [has_child] => 0
                    [is_group] => 1
                    [is_dynamic] => 1
                    [dynamic_query] => 
                    [assign_to_id] => 
                    [created_by] => 1
                    [modified_by] => 1
                    [deleted] => 0
                )

        )

)


So I want to show this one because group_id=1, the other two conditions seem to work of ā€œis adminā€ and ā€œcreated byā€ Itā€™s just this one thatā€™s not returning true on this line:

if ($item->is_group == 1 || $item[ā€˜created_byā€™] === $user->id || is_admin($user)) {

Iā€™ve tried a bunch of different things and just canā€™t get it to return true for ā€œis_groupā€ Iā€™m sure itā€™s PHP 101 type thing, I just canā€™t get it.

Iā€™ve tried this too and it doesnā€™t return true:

if ($item['is_group'] === 1 || $item['created_by'] === $user->id ) {

I think I got it!!!

 if ($item['is_group'] === '1' || $item['created_by'] === $user->id || is_admin($user)) {

This works and shows subscribed folders that are marked as ā€œis_groupā€ =1 Now I just have to tackle the problem of why the ā€œis_groupā€ is not getting populated when a group account is created.

I updated the bug here: Accessing Group Mailboxes Does Not Work Ā· Issue #9028 Ā· salesagility/SuiteCRM Ā· GitHub

Great work Paul :tada:

The strict comparison === requires that the data types are exactly the same, not just ā€œequivalentā€. I am not sure, but perhaps it would be better, instead of giving it the string datatype with === '1' like you did, to just relax the comparison to == 1.

This would depend on the rest of the code that writes the value into the array.

Itā€™s possible that a similar issue is breaking the code regarding the other issues you found.

Writing $item['is_group'] should be equivalent here to $item->is_group.

So, if this works, thatā€™s how Iā€™d suggest leaving it:

$item->is_group == 1.

1 Like

Thanks for that insight! I was going crazy why it didnā€™t return true. I never even thought to look at the equivalency. I tried your suggestion, it does not return true. However, I modified my change to be less restrictive as you suggest, and it works, and also the other issue I was having was after the change it was crashing out the folder selection in the user profile. That seems to work. Iā€™ll do some more testing around this. Also my next problem is that when you create or update a group account, it doesnā€™t write ā€œis_groupā€ = 1 to the folders table. Iā€™m going to work on that next.

Here is the modified line that works:

if ($item['is_group'] == 1 || $item['created_by'] === $user->id || is_admin($user)) {

1 Like

Ok for those following along in this threadā€¦ Whooo hoo! Iā€™ve solved the second problem that group email folders donā€™t get marked with ā€œis_group=1ā€ when create or updated. So now with the below and my previous change, users should see group email folders .

Still issues:

  1. I noticed inbound email folders donā€™t get deleted when the inbound email account is deleted. Iā€™ll have to figure that out.
  2. In the user settings, selecting the subscribed folders does not save correctly and gives user access to all group folders.

Anyway, hereā€™s what Iā€™ve done to fix the ā€œis_groupā€ problem.

public function save($addSubscriptions = true)
    {
		 $this->dynamic_query = $this->db->quote($this->dynamic_query);

// //////////////////////////////////////////////////////////////CHANGE		
// Retrieve the value of 'is_personal' for the current folder
 // Check if the current folder is a parent folder
if (!empty($this->parent_folder)) {
    $query2 = "SELECT is_personal FROM inbound_email WHERE id = " . $this->db->quoted($this->parent_folder);
} else {
    $query2 = "SELECT is_personal FROM inbound_email WHERE id = " . $this->db->quoted($this->id);
}

$r2 = $this->db->query($query2);
$is_personal = $this->db->fetchByAssoc($r2)['is_personal'];

// Set the value of 'is_group' based on the value of 'is_personal'
if ($is_personal == 1) {
    $is_group = 0;
} else {
    $is_group = 1;
}

////////////////////////////////////END  CHANGES
    

        if ((!empty($this->id) && $this->new_with_id == false) || (empty($this->id) && $this->new_with_id == true)) {
            if (empty($this->id) && $this->new_with_id == true) {
                $guid = create_guid();
                $this->id = $guid;
            }

            $query = "INSERT INTO folders (id, name, folder_type, parent_folder, has_child, is_group, " .
                 "is_dynamic, dynamic_query, assign_to_id, created_by, modified_by, deleted) VALUES (" .
                    $this->db->quoted($this->id) . ", " .
                    $this->db->quoted($this->name) . ", " .
                    $this->db->quoted($this->folder_type) . ", " .
                    $this->db->quoted($this->parent_folder) . ", " .
                    $this->db->quoted($this->has_child) . ", " .
					////////////////////////////////////////////////////////CHANGE
                //    $this->db->quoted($this->is_group) . ", " .//remove
				  $this->db->quoted($is_group) . ", " . // set the value of is_group here
				//////////////////////////////////////////////////////////////END CHANGE	
                    $this->db->quoted($this->is_dynamic) . ", " .
                    $this->db->quoted($this->dynamic_query) . ", " .
                    $this->db->quoted($this->assign_to_id) . ", " .
                    $this->db->quoted($this->currentUser->id) . ", " .
                    $this->db->quoted($this->currentUser->id) . ", 0)";

            if ($addSubscriptions) {
                // create default subscription
                $this->addSubscriptionsToGroupFolder();
            }

            // if parent_id is set, update parents has_child flag
            if (!empty($this->parent_folder)) {
                $query3 = "UPDATE folders SET has_child = 1 WHERE id = " . $this->db->quoted($this->parent_folder);
                $r3 = $this->db->query($query3);
            }
        } else {
            $query = "UPDATE folders SET " .
                "name = " . $this->db->quoted($this->name) . ", " .
                "parent_folder = " . $this->db->quoted($this->parent_folder) . ", " .
                "dynamic_query = " . $this->db->quoted($this->dynamic_query) . ", " .
                "assign_to_id = " . $this->db->quoted($this->assign_to_id) . ", " .
                "modified_by = " . $this->db->quoted($this->currentUser->id) . ", " .
				// CHANGE

				 "is_group = " . $is_group . " " .

				 // END CHANGE
                "WHERE id = " . $this->db->quoted($this->id);
        }

        return $this->db->query($query, true);
    }
2 Likes

Ok working on problem #3:When an inbound email account is deleted it doesnā€™t remove them from the folders table or the folders_subscription table and the users can see deleted inbound accounts in their listview (assuming 1 and 2 are fixed above) . There is a function to do this in SugarFolders.php but is never gets called.

I found that when an inbound email address getā€™s deleted, it runs \suitecrm\modules\InboundEmail/Delete.php

This is great! Now I know where to call the function delete() from SugarFolders.php.

HOWEVER, there is no relationship between the inbound email account and the Folders!!!

I donā€™t know how to pass the ID of the parent folder because there is no relation I can see to the inbound email account!

As an example Inbound email account ID = 9fd6f2b6-d27e-3a30-3860-646916d7b037
It has: Group Folder ID = 995b9d97-1d42-ef53-d1a6-64691630c162
and Group ID = 9959fa3c-0e7f-103d-5416-6469165df7eb (in inbound_email table)

Neither of which correspond to anything else in the database!

The ID of the parent folder (in folders table) that should be related to this is:
a6ae099b-15d2-f2bc-9a67-64691642f9bf

Thereā€™s no way to ID the folders to be deleted from the inbound email account. I guess I could look for the email address, but thatā€™s not exact. Am I missing something does anyone know how Iā€™d relate the Inbound email record in the DB to the folder record? (youā€™d think it would be by group folder ID but itā€™s not!). Maybe thatā€™s another problem!!! When folders get created youā€™d think the group folder ID should reference the inbound email account ID.

In Inbound_email, did you look inside the BASE64 encoded field? I think itā€™s called stored_options

Thanks @pgr I was hoping you put me on the trail, but alas, no. Thereā€™s got to be a way!

Hereā€™s whatā€™s in the base64 encode.

a:13:{s:9:"from_name";s:6:"Reply4";s:9:"from_addr";s:30:"reply@igosalesandmarketing.com";s:13:"reply_to_name";s:6:"Reply4";s:13:"reply_to_addr";s:30:"reply@igosalesandmarketing.com";s:10:"only_since";b:0;s:13:"filter_domain";s:0:"";s:30:"email_num_autoreplies_24_hours";s:2:"10";s:26:"allow_outbound_group_usage";b:1;s:7:"mailbox";s:5:"INBOX";s:11:"trashFolder";s:11:"INBOX.Trash";s:10:"sentFolder";s:10:"INBOX.Sent";s:12:"isAutoImport";b:1;s:25:"leaveMessagesOnMailServer";i:1;}

Iā€™m thinking to use the email address to match. I donā€™t really like that because it stores the email login (which in most cases is the email address) to match the folder. So Iā€™d have to match on email address and is_group =1. I think that would pretty much limit it. Iā€™d much rather match on an ID. I was thinking in a case for example where a user added sales@domain.com as a personal and the admin also setup a group account sales@domian.com. I guess though if I limit it to is_group=1 and deleted=0 then for the most part, Iā€™m getting the right parent folder associated with the email account. It would be so much easier if there was a key to match on. Itā€™s too bad the groupfolder_id isnā€™t the inbound email account ID.

Ok got it duh, the ā€œinboxā€ folder ID = the inbound account id and then the sub folders, have a parent ID of the inbox folder!!! OK this works. I was looking at the top level folder. Not sure why this has a different ID, but anyway, I think I can use to solve.

1 Like

Paul, I think itā€™s great that youā€™re taking the time to really dive into this.

If you have any PHP questions that I can help with, feel free to ask. My time is well spent helping you because you help others, and because youā€™re clearly a good learner and making good progress as a developer. :muscle:

1 Like

Thanks @pgr, youā€™ve been a huge help over the years with SuiteCRM and given me just the right kind of feedback to keep me going in the right direction. While Iā€™ve done a lot of front end web stuff with HTML and CSS, Iā€™ve been really learning a lot of PHP over the last year or so mostly. Diving into these kinds of problems really helps me learn a ton, plus itā€™s the least I can do to give back to the community for a great CRM! I get most of the coding structures, (I learned them on a PET computer in BASIC 40 years ago if you can believe it!), I just donā€™t have the day to day experience with all the syntax of PHP yet, which is where I struggle.

1 Like

Still trying to get the deleted folders of a deleted email account marked as deleted. There seems to be functionality to do this in SugarFolders.php = public function delete()

Ok, I think Iā€™m fundamentally misunderstanding something here.

When an inbound email account gets deleted. modules/InboundEmail/delete.php is called. Great.

I need to now run delete() public function in /include/SugarFolders/SugarFolders.php

Iā€™ve already figured out how to get $inboundEmailID of the current account being deleted and the $current_user.

Iā€™m trying to call the public function delete like thisā€¦

require_once('include/SugarFolders/SugarFolders.php');
$sugarFolders = new SugarFolder();

$sugarFolders->id = $inboundEmailId; // Set the ID of the folder to be deleted
$sugarFolders->currentUser = $current_user; // Set the current user object
$sugarFolders->delete();

I have an object when I echo out $sugarFolders, but the delete function is just not getting executed (I have a log there too).

Not sure, do I need to do something like $sugarFolders->retrieve($inboundEmailId); first (I tried that too and didnā€™t work)?

Ok, making progress! Never fails, as soon as I post a question another idea pops into my head.

Ok so trying to set the currentUser messed it up.

require_once('include/SugarFolders/SugarFolders.php');
$sugarFolder = new SugarFolder();

$sugarFolder->retrieve($inboundEmailId); // Get the folder to be deleted

$sugarFolder->delete();

}

Whoo hoo! delete is now being executed. Still not marking the folders deleted = ā€œ1ā€ but thatā€™ s tomorrowā€™s problem. Now I have to troubleshoot the delete() function and deleteChildrenCascade() function.

I would try (in the new SugarFolders command) calling the constructor with as many arguments as you have available.

Check those defaults there, no use in passing values if they are the same as those.

You can see thereā€™s preparatory code there in the constructor, you should get a more functional object if you initialize it properly, not just add values to member properties.

Thanks @pgr problem #3 solved. Iā€™ve successfully called the delete() function and it works as intended without any further modification. All related folders to the parent INBOX that is being deleted get marked deleted =1, including the parent INBOX folder. Ok on to problem #4.

This is what I added to Delete.php. Iā€™m going to to a pull request. Iā€™ve tested a couple of times. Just want to test with a user that is not admin and see what happens.

//delete related folders by calling delete() in SugarFolders.php
// Retrieve the ID of the inbound email account being deleted
$inboundEmailId = $focus->id;

// Create an instance of the SugarFolders class

require_once('include/SugarFolders/SugarFolders.php');
$sugarFolder = new SugarFolder();

$sugarFolder->retrieve($inboundEmailId); // Get the folder to be deleted

$sugarFolder->delete();

}