As mentioned before, the WhoId and WhatId fields on Task are Polymorphic (meaning that they can point to multiple target objects. Unless you have the SOQL Polymorphism feature enabled, as @eyescream describes, the only "related" fields that you can query for are those that are on the 'Name' API object, but there are exceptions, which are documented on this document.
Example 1: select Who.FirstName, Who.LastName, Who.Email from Task
This will return data for FirstName and LastName if the Contact/Lead has those fields populated, but, as the above document says, it will never return results for Who.Email, because neither of the two possible target objects of the Who
field (Contact,Lead) is the User
object.
Example 2: select Owner.Name, Owner.Email from Case
If you are using Queues with the Case object, then a Case's Owner can be either a User or a Group (of which a Queue is a type) record. Because both Name
and Email
are on the Name
object, the above query will always return data for Name and, if the target object is a User, it WILL return data for Owner.Email.
Example 3: select What.Name, WhatId from Task where What.Type in ('Case','Account','Solution')
This is a very interesting example because the Case object's "Name" field is actually CaseNumber
, not Name --- there are a couple other standard objects with "non-standard" (ironic) Name fields, e.g. SolutionTitle, and then there are others that don't even have Name fields, like CampaignMember
. HOWEVER, one of the great things about Salesforce having polymorphic fields technically point to the Name
object is that the above query WILL return results for Cases! If a Case's CaseNumber is 00001234, then What.Name in the above query will return 00001234, whereas for an Account it will return the Account's Name, and for a Solution it will return SolutionTitle.
It is also helpful to observe here that you CAN limit which target objects are returned by filtering on the 'Type' field, which is a special field on the Name
object.