I'm going to have to write a custom controller for a Visualforce email to pull back details for the contract where my "send email" button will be hosted. My relatedtotype is the Account object (has to be this way because of the amount of related information to Account that I need to pull) if that at all helps.

I was hoping it would be a simple SOQL of:

SELECT <fields 1 - 20> FROM Contracts WHERE id = get.id 

or something similar.

I'm afraid my syntax knowledge is lacking and that is why I'm coming to you!

Fingers crossed my life will be:

  1. Apex to host this SOQL
  2. VisualforceComponent to bring in the result
  3. Tie into Visualforce email

Feel free to let me know if my logic is lacking!

UPDATE 1: (now deleted to reduce length, superseded by next update)


I am working on the custom controller. So far I have the following Apex Controller:

public class findContract {

public Id conID {get; set;}

    Public List<Contract> currentcontract = new List<Contract>();

    public List<Contract> getcurrentcontract() {
        currentcontract = [SELECT Id, StartDate, Business_Type__c, Affinity__c, ContractTerm,  CompanySigned.name, CompanySignedDate, CustomerSigned.name, CustomerSignedDate, CustomerSignedTitle, 
        EndDate, Services_Taken_AI_Only__c, Services_Taken_AI_Only_HS__c, Services_Taken_Advice_Only__c, Services_Taken_Advice_Only_HS__c, Services_Taken_Franchise_Comp_EL__c, 
        Services_Taken_Franchise_Comp_HS__c, Services_Taken_Consultancy__c, Services_Taken_Franchise_Entry_EL__c, Services_Taken_Env__c, 
        Services_Taken_eRAMS__c, Services_Taken_FRA__c, Services_Taken_HS__c, Services_Taken_SBP__c, Services_Taken_Training__c, Services_Taken_JIT__c, H_S_Notes__c, 
        Finance_Notes__c, PEL_Notes__c, SpecialTerms FROM Contract WHERE Id = '800D00000044RXCIA2'];    //:conID
        return currentcontract ;

I've hard coded the ID because I just want to get something to display to start with, I'm getting nothing right now.

In the Component, I have this:

<apex:component controller="findContract" access="global">
    <apex:attribute name="ContractId" description="This is the Contract Id." type="Id" assignTo="{!conID}"/>     
    <table border="1">
            <td><apex:outputText value="Contract Term"/></td>
            <td><apex:outputText value="Start Date"/></td>
            <td><apex:outputText value="Business Type"/></td>
            <td><apex:outputText value="Affinity"/></td>
    <apex:repeat value="{!currentcontract}" var="con" id="theRepeat">
            <td><apex:outputField value="{!con.ContractTerm}"/></td>
            <td><apex:outputField value="{!con.StartDate}"/></td>
            <td><apex:outputField value="{!con.Business_Type__c}"/></td>
            <td><apex:outputField value="{!con.Affinity__c}"/></td>

It is as if nothing is coming through from the Apex Controller.

And the VF email:

<c:DisplayContractDetails ContractID="800D00000044RXCIA2"/>

Again, something basic with hardcoded values that aren't even being used yet. I am just not seeing anything returned on the email.

I know the SOQL is fine because I have run it through Force Explorer - I just cannot see where to go next right now. I've tried system.debug but nothing shows up.

  • 1
    More info is needed 1) Is button on Account detail page? or if not, where? 2) One Account can have many Contracts so how are you dealing with that? – cropredy Dec 22 '14 at 17:49
  • It is on the Contract screen. Hence hoping I can draft in the ID for the Apex to use simply. Most of the email is sufficiently created using Account as the RelatedToType. I can pull in everything I want from there and using Apex Repeat to hit up the related objects. Contracts is the only bugbear because I must return information specific to the contract in question only. – 44f Dec 23 '14 at 9:24
  • So I see your update. Does this mean that you were able to get the information from the query in your controller, and you're only having a problem getting it to display properly now? I'm not seeing a reference to Contract or conID in your visualforce code, so I'm a bit confused. If you could describe what you have working, and what still isn't working at this point, that would help. – Shane Steinfeld Dec 23 '14 at 20:51
  • Done ANOTHER update above. Returning to this post holidays. Let me know if the above is still true for my code. – 44f Jan 5 '15 at 15:28

You can't actually use a controler (directly) from a visualforce email template. Instead, you'll need to write a visualforce component, and include the component in your template. (You can write a controller for the component, but not for the email template.)

crop1645's question about having multiple contracts associated with an account is important to consider too.

Here's how I would approach this:

  • Create a very basic email template containing a custom component. (Plan on putting most of the dynamic content in the component, not the template.)
  • Make the relatedToType of your email template "Contract" (instead of "Account"). That way you'll know exactly which Contract you're dealing with.
  • Pass the Contract ID into the component so you'll be able to reference it from the component's controller.
  • In the controller, you can use the Contract ID to query for any info you need from the Contract and it's associated Account. Use that info to design your email inside the component.

Something like this:

Email template:

<messaging:emailTemplate relatedToType="Contract" subject="...">
      Lorem Ipsum dolor bla bla bla...
      <c:EmailBodyContent theContractID="{!relatedTo.ID}">

Visualforce component: (EmailBodyContent.component)

<apex:component access="global" controller="myController">
  <apex:attribute name="theContractID" description="..." type="string" assignTo="{!conID}"/>
    Regarding the contract starting on {!theContract.StartDate} for {!theAccount.Name}...

Component controller

Public class myController{
  public String conID {get; set;}
  public Account theAccount {get; set;}
  public Contract theContract {get; set;}

  theContract = [SELECT Id, StartDate, AccountID FROM Contract WHERE Id = :conID LIMIT 1];
  theAccount = [SELECT Id, Name FROM Account WHERE Id = :theContract.AccountID LIMIT 1];
  • Ok, I have started scribing this. I am struggling in making the three elements. I'll detail that in an edit. – 44f Jan 5 '15 at 15:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.