What is better to use for this case, a CTE or a table variable?
I would probably do it this way, using set-based dynamic SQL instead of any looping constructs, CTEs, etc. We could probably eliminate the table variable as well, but not enough information in the question for that, so this code assumes the table variable is already populated. 

DECLARE @sql NVARCHAR(MAX) = N'';

SELECT @sql += N'
EXEC msdb.dbo.sp_send_dbmail 
  @profile_name = @profileName, 
  @recipients = N''recipientlist'', 
  @subject = N''someSubject'', @body = N''' 
    + col1 + N' and ' 
    + col2 + N' and ' 
    + col3 + N' are the columns'';'
FROM @tableVar1;

EXEC sys.sp_executesql @sql, N'@profileName SYSNAME', @profileName;