I am unsure if you can attach file(s) to emails sent from a workflow. However, if you decide to do so via apex code instead of the workflow, you can do so as follows:
// Create the data string that will become the csv body
public String csvBody() {
String strOf = '\"';
// Create the headers (these are not automatically added)
for (String downloadField : downloadFields) {
strOf += mapFieldLabels.get(downloadField) + '\",\"';
}
strOf += '\"\n';
// Create the data rows (these are not automatically added)
// "getFullResults()" is a Database.query() result cast to List<sObject>
for (sObject result : getFullResults()) {
strOf += '\"';
for (String downloadField : downloadFields) {
// If the field is a reference field, lookup the ".Name" version, otherwise this will simply populate the Id (you can still get the Id by requesting Account.Id instead of AccountId)
// "field" is obtained dynamically since "Account.ParentId" does not work in a get() method
if (mapSObjectFields.get(UtilsGeneral.getLookupSObjectName(strSObjectName, downloadField)).get(UtilsGeneral.getLookupFieldName(downloadField).toLowerCase()).getDescribe().getType() == DisplayType.Reference && UtilsGeneral.getRecursive(result, downloadField) != null) {
if (downloadField.right(3) == '__c') {
downloadField = downloadField.left(downloadField.length() - 3) + '__r.Name';
} else if (downloadField.right(2) == 'Id' && downloadField.length() > 2) {
downloadField = downloadField.left(downloadField.length() - 2) + '.Name';
}
}
// populate the field only if != null (without this logic check, "null" will appear in the csv field)
// the "getRecursive()" method is required since "Account.ParentId" does not work in a get() method...
if (UtilsGeneral.getRecursive(result, downloadField) != null) strOf += UtilsGeneral.getRecursive(result, downloadField);
strOf += '\",\"';
}
strOf += '\"\n';
}
return strOf;
}
// Create an attachment from the string created above and attach it to an email and send
public void sendEmail() {
String csvName = 'export';
Messaging.EmailFileAttachment csvAttc = new Messaging.EmailFileAttachment();
blob csvBlob = Blob.valueOf(csvBody());
csvAttc.setFileName(csvName + '.csv');
csvAttc.setBody(csvBlob);
Messaging.SingleEmailMessage email = new Messaging.SingleEmailMessage();
List<String> toAddresses = new List<String>{UserInfo.getUserEmail()};
String subject = csvName;
email.setSubject(subject);
email.setToAddresses(toAddresses);
email.setPlainTextBody('Attached you will find a csv containing the data you just requested from salesforce.com: ' + csvName + '.csv\n\nThank you,\n\nSales Operations');
email.setFileAttachments(new List<Messaging.EmailFileAttachment>{csvAttc});
List<Messaging.SendEmailResult> r = Messaging.sendEmail(new List<Messaging.SingleEmailMessage>{email});
}
mapSObjectFields
is a Map<String, Map<String, Schema.SObjectField>>
filled with the Schema.getGlobalDescribe().get(sObjectName).getDescribe().fields.getMap()
for the sObject(s) you are querying (must also include the sObjects that are referenced dynamically within, i.e. if you are querying the Opportunity
sObject and refer to Account.ParentId
, mapSObjectFields
must include the getMap()
for both Account
and Opportunity
)
mapSObjectFieldLabels
is a Map<String, Map<String, String>>
filled with the Schema.SObjectField.getLabel()
for the sObject(s) you are querying (same data as mapSObjectFields
, but with getLabel()
instead of the Schema.SObjectField
as the result)
**If you need help with mapSObjectFields
or mapSObjectFieldLabels
, feel free to ask... The variable { get; set; } parameters were too hefty to post here...
The methods required to run this:
public static Object getRecursive(sObject record, String fieldName) {
if(fieldName.contains('.')) {
Integer firstPeriod = fieldName.indexOf('.');
String nextSObjectName = fieldName.subString(0, firstPeriod);
String nextfieldName = fieldName.subString(firstPeriod + 1, fieldName.length());
sObject nextRecord = record.getSObject(nextSObjectName);
if(nextRecord == null) {
return null;
} else {
return getRecursive(nextRecord, nextfieldName);
}
} else {
return record.get(fieldName);
}
}
public static String getLookupFieldName(String fieldName) {
if (fieldName.contains('.')) {
fieldName = fieldName.subString(fieldName.indexOf('.', fieldName.countMatches('.') - 1) + 1, fieldName.length());
}
return fieldName;
}
public static String getLookupSObjectName(String sObjectName, String fieldName) {
String relationshipName = '';
system.debug('getLookupSObjectName().start() = ' + sObjectName);
if (fieldName.contains('.')) {
Map<String, Schema.SObjectType> globalDescribe = Schema.getGlobalDescribe();
Map<String, Map<String, Schema.SObjectField>> mapSObjectFields = new Map<String, Map<String, Schema.SObjectField>>();
mapSObjectFields.put(sObjectName, new Map<String, Schema.SObjectField>());
mapSObjectFields.get(sObjectName).putAll(globalDescribe.get(sObjectName).getDescribe().fields.getMap());
for (Integer i = 0; i < fieldName.countMatches('.'); i++) {
Integer firstCharacter = 0;
if (i > 0) firstCharacter = fieldName.indexOf('.', i - 1) + 1;
Integer lastCharacter = fieldName.indexOf('.', i);
relationshipName = fieldName.subString(firstCharacter, lastCharacter);
if (relationshipName.right(3) == '__r') {
relationshipName = relationshipName.left(relationshipName.length() - 3) + '__c';
} else {
relationshipName = relationshipName + 'Id';
}
relationshipName = relationshipName.toLowerCase();
sObjectName = mapSObjectFields.get(sObjectName).get(relationshipName).getDescribe().referenceTo[0].getDescribe().getName();
fieldName = fieldName.subString(lastCharacter + 1, fieldName.length());
if (!mapSObjectFields.containsKey(sObjectName)) {
mapSObjectFields.put(sObjectName, new Map<String, Schema.SObjectField>());
mapSObjectFields.get(sObjectName).putAll(globalDescribe.get(sObjectName).getDescribe().fields.getMap());
}
}
system.debug('getLookupSObjectName().end() = ' + sObjectName);
}
return sObjectName;
}