How can I simplify a nested foreach

I think I took longer to try to think of a title that summarized this than I did on explaining the actual problem. x_x

I have a function with nested foreach loops that I would like to simplify or at least make re-usable. In this sample, each friends property is of type List<Person>.

void InviteFriendsToParty(Person p) {
    foreach (Person e in p.friends) 
        foreach (Person r in e.friends) 
            foreach (Person s in r.friends) 
                foreach (Person o in s.friends) 
                    SendInvitation(o); }

Is it possible to convert this to such a function that I can pass in a source Person p and an int depth and let the nested foreach part be dynamically sized? I’ve tried a couple of variations, but I think I’ve been trying to overcomplicate it for so long that I’m missing something really simple.

Something like this could work

void InviteFriendsToParty(Person p, int depth) {
     foreach (Person e in p.friends) {
          if (depth == 0) {
                SendInvitation(e);
          } else {
                InviteFriendsToParty(e, --depth);
          }
     }
}

You could make it more reusableby parameterizing the function that should be called at the end.

void DoToFriendsRecursive(Person p, Action<Person> action, int depth) {
         foreach (Person e in p.friends) {
              if (depth == 0) {
                    action(e);
              } else {
                    DoToFriendsRecursive(e, action, --depth);
              }
         }
    }

I’m just guessing here but you probably need either a depth limit like in my example or some way to detect and terminate endless loops. If A is friend of B who’s friend of C who’s friend of A, they will send invites in a circle unless you specifically stop it