您可以使用电子邮件服务来处理 入站电子邮件。例如,您可以创建自动创建的电子邮件服务 基于邮件中的联系人信息的联系人记录。您可以将每个电子邮件服务与一个或多个 Salesforce 生成的电子邮件相关联 用户可以向其发送消息进行处理的地址。授予多个用户访问权限 对于单个电子邮件服务,您可以:
- 关联多个 Salesforce 生成的电子邮件地址与电子邮件服务并分配 这些地址给用户。
 - 关联单个 Salesforce 生成的 电子邮件地址,并编写一个执行 根据访问电子邮件服务的用户。例如,您可以 编写一个 Apex 类,该类根据用户的电子邮件地址标识用户 并代表该用户创建记录。
 
要使用电子邮件服务,请从“设置”中输入“快速查找”框,然后选择“电子邮件” 服务。
Email Services
- 单击“新建电子邮件服务”以定义新电子邮件 服务。
 - 选择现有电子邮件服务以查看其配置,激活或 停用它,然后查看或指定该电子邮件服务的地址。
 - 单击“编辑”以对现有电子邮件进行更改 服务。
 - 单击“删除”以删除电子邮件服务。注意以前 删除电子邮件服务,您必须删除所有关联的电子邮件服务 地址。
 
什么时候 定义电子邮件服务时,请注意以下几点:
- 电子邮件服务仅处理在其 地址。
 - Salesforce 限制 所有电子邮件服务(包括按需电子邮件到案例)都可以处理 日常。超过此限制的邮件将被退回、丢弃或排队等待 第二天处理,具体取决于您如何为每个电子邮件服务配置失败响应设置。Salesforce 通过将 用户许可证数量增加 1,000 个;最大 1,000,000。例如,如果您有 10 个许可证,您的组织最多可以处理 10,000 封电子邮件 日。
 - 您在沙盒中创建的电子邮件服务地址无法复制到 生产组织。
 - 对于每个电子邮件服务,您可以告诉 Salesforce 将错误电子邮件发送到 指定的地址,而不是发件人的电子邮件地址。
 - 电子邮件服务拒绝电子邮件并通知发件人 如果电子邮件(正文文本、正文 HTML 和附件组合)超过 大约25兆字节 (因语言和性格而异 设置).
 
使用 InboundEmail 对象
对于 Apex 电子邮件服务域收到的每封电子邮件,Salesforce 都会创建一个单独的 包含该电子邮件的内容和附件的 InboundEmail 对象。你可以使用 实现接口以处理入站电子邮件的 Apex 类。 使用该类中的方法, 您可以访问 InboundEmail 对象来检索 入站电子邮件,以及执行许多功能。
Messaging.InboundEmailHandlerhandleInboundEmail
示例 1:为联系人创建任务
以下示例说明了如何根据入站查找联系人 电子邮件地址并创建一个新任务。
public with sharing class CreateTaskEmailExample implements Messaging.InboundEmailHandler {
 
  public Messaging.InboundEmailResult handleInboundEmail(Messaging.inboundEmail email, 
                                                       Messaging.InboundEnvelope env){
 
    // Create an InboundEmailResult object for returning the result of the 
    // Apex Email Service
    Messaging.InboundEmailResult result = new Messaging.InboundEmailResult();
  
    String myPlainText= '';
    
    // Add the email plain text into the local variable 
    myPlainText = email.plainTextBody;
   
    // New Task object to be created
    Task[] newTask = new Task[0];
   
    // Try to look up any contacts based on the email from address
    // If there is more than one contact with the same email address,
    // an exception will be thrown and the catch statement will be called.
    try {
      Contact vCon = [SELECT Id, Name, Email
        FROM Contact
        WHERE Email = :email.fromAddress
        WITH USER_MODE
        LIMIT 1];
      
      // Add a new Task to the contact record we just found above.
      newTask.add(new Task(Description =  myPlainText,
           Priority = 'Normal',
           Status = 'Inbound Email',
           Subject = email.subject,
           IsReminderSet = true,
           ReminderDateTime = System.now()+1,
           WhoId =  vCon.Id));
     
     // Insert the new Task 
     insert as user newTask;    
     
     System.debug('New Task Object: ' + newTask );   
    }
    // If an exception occurs when the query accesses 
    // the contact record, a QueryException is called.
    // The exception is written to the Apex debug log.
   catch (QueryException e) {
       System.debug('Query Issue: ' + e);
   }
   
   // Set the result to true. No need to send an email back to the user 
   // with an error message
   result.success = true;
   
   // Return the result for the Apex Email Service
   return result;
  }
}
示例 2:处理退订电子邮件
向客户和潜在客户发送营销电子邮件的公司必须提供 让收件人退订的方式。以下是电子邮件如何 服务可以处理退订请求。该代码搜索 “取消订阅”一词的入站电子邮件。如果找到该单词,则 代码查找与发件人电子邮件地址匹配的所有联系人和潜在顾客,并将电子邮件选择退出字段 () 设置为 True。HasOptedOutOfEmail
public with sharing class unsubscribe implements Messaging.inboundEmailHandler{
    public Messaging.InboundEmailResult handleInboundEmail(Messaging.InboundEmail email, 
                         Messaging.InboundEnvelope env ) {
    
        // Create an inboundEmailResult object for returning 
        // the result of the email service.
        Messaging.InboundEmailResult result = new Messaging.InboundEmailResult();
         
        // Create contact and lead lists to hold all the updated records.
        List<Contact> lc = new List <contact>();
        List<Lead> ll = new List <lead>();
         
        // Convert the subject line to lower case so the program can match on lower case.
        String mySubject = email.subject.toLowerCase();
        // The search string used in the subject line.
        String s = 'unsubscribe';
         
        // Check the variable to see if the word "unsubscribe" was found in the subject line. 
        Boolean unsubMe;
        // Look for the word "unsubcribe" in the subject line. 
        // If it is found, return true; otherwise, return false.
        unsubMe = mySubject.contains(s);
         
         // If unsubscribe is found in the subject line, enter the IF statement.
         
        if (unsubMe == true) {
            
            try {
               
            // Look up all contacts with a matching email address.
               
            for (Contact c : [SELECT Id, Name, Email, HasOptedOutOfEmail
                          FROM Contact
                          WHERE Email = :env.fromAddress
                          AND hasOptedOutOfEmail = false
                          WITH USER_MODE
                          LIMIT 100]) {
                          
                // Add all the matching contacts into the list.   
                c.hasOptedOutOfEmail = true;
                lc.add(c);
            }
            // Update all of the contact records.
            update as user lc;
        }
        catch (System.QueryException e) {
            System.debug('Contact Query Issue: ' + e);
        }   
        
        try {
            // Look up all leads matching the email address.
            for (Lead l : [SELECT Id, Name, Email, HasOptedOutOfEmail
                     FROM Lead
                     WHERE Email = :env.fromAddress
                     AND isConverted = false
                     AND hasOptedOutOfEmail = false
                     WITH USER_MODE
                     LIMIT 100]) {
                // Add all the leads to the list.       
                l.hasOptedOutOfEmail = true;
                ll.add(l);
                   
                System.debug('Lead Object: ' + l);   
            } 
            // Update all lead records in the query.
            update as user ll;
        }
        
        catch (System.QueryException e) {
            System.debug('Lead Query Issue: ' + e);
        }   
        
        System.debug('Found the unsubscribe word in the subject line.');
         } 
         else {
            System.debug('No Unsuscribe word found in the subject line.' );
         }
        // Return True and exit.
        // True confirms program is complete and no emails 
        // should be sent to the sender of the unsubscribe request. 
        result.success = true;
        return result;
    }   
}
@isTest
private class unsubscribeTest {
    // The following test methods provide adequate code coverage 
    // for the unsubscribe email class.
    // There are two methods, one that does the testing
    // with a valid "unsubcribe" in the subject line
    // and one the does not contain "unsubscribe" in the
    // subject line.        
    static testMethod void testUnsubscribe() {
    
       // Create a new email and envelope object.
       Messaging.InboundEmail email = new Messaging.InboundEmail() ;
       Messaging.InboundEnvelope env    = new Messaging.InboundEnvelope();
    
       // Create a new test lead and insert it in the test method.
       Lead l = new lead(firstName='John', 
                lastName='Smith',
                Company='Salesforce', 
                Email='user@acme.com', 
                HasOptedOutOfEmail=false);
       insert l;
    
       // Create a new test contact and insert it in the test method.
       Contact c = new Contact(firstName='john', 
                    lastName='smith', 
                    Email='user@acme.com', 
                    HasOptedOutOfEmail=false);
       insert c;
       
       // Test with the subject that matches the unsubscribe statement.
       email.subject = 'test unsubscribe test';
       env.fromAddress = 'user@acme.com';
       
       // Call the class and test it with the data in the testMethod.
       unsubscribe unsubscribeObj = new unsubscribe();
       unsubscribeObj.handleInboundEmail(email, env );
                            
    }
     
    static testMethod void testUnsubscribe2() {
    
       // Create a new email and envelope object.
       Messaging.InboundEmail email = new Messaging.InboundEmail();
       Messaging.InboundEnvelope env = new Messaging.InboundEnvelope();
    
       // Create a new test lead and insert it in the test method.        
       Lead l = new lead(firstName='john', 
                lastName='smith',
                Company='Salesforce', 
                Email='user@acme.com', 
                HasOptedOutOfEmail=false);
       insert l;
    
       // Create a new test contact and insert it in the test method.    
       Contact c = new Contact(firstName='john', 
                    lastName='smith', 
                    Email='user@acme.com', 
                    HasOptedOutOfEmail=false);
       insert c;
       
       // Test with a subject that does not contain "unsubscribe."
       email.subject = 'test';
       env.fromAddress = 'user@acme.com';
    
       // Call the class and test it with the data in the test method.
       unsubscribe unsubscribeObj = new unsubscribe();
       unsubscribeObj.handleInboundEmail(email, env );                      
       // Assert that the Lead and Contact have been unsubscribed
       Lead updatedLead = [Select Id, HasOptedOutOfEmail from Lead where Id = :l.Id];
       Contact updatedContact = [Select Id, HasOptedOutOfEmail from Contact where Id = :c.Id];
       Assert.isTrue(l.HasOptedOutOfEmail);
       Assert.isTrue(c.HasOptedOutOfEmail);
    }     
}
Visualforce 类
除了使开发人员能够向 Salesforce 添加业务逻辑之外 系统事件,例如按钮点击和相关记录更新,Apex 也可用于 通过自定义 Visualforce 控制器为 Visualforce 页面提供自定义逻辑,以及 控制器扩展。
- 自定义控制器是用 Apex 编写的类,它实现了页面的所有 逻辑,而无需使用标准控制器。如果您使用自定义控制器,则 可以定义新的导航元素或行为,但还必须重新实现任何 标准控制器中已提供的功能。像其他 Apex 一样 类,自定义控制器完全在系统模式下执行,其中对象 并且忽略当前用户的字段级权限。您可以指定 用户是否可以根据用户的 轮廓。
 - 控制器扩展是用 Apex 编写的类,用于添加或覆盖行为 在标准或自定义控制器中。扩展允许您利用 另一个控制器的功能,同时添加您自己的自定义逻辑。因为 标准控制器在用户模式下执行,其中权限为字段级 安全性,并强制执行当前用户的共享规则,从而扩展了 标准控制器允许您构建尊重用户的 Visualforce 页面 权限。尽管扩展类在系统模式下执行,但标准 控制器在用户模式下执行。与自定义控制器一样,您可以指定 用户是否可以根据用户的 轮廓。
 
在构建自定义 Visualforce 时,可以使用这些系统提供的 Apex 类 控制器和控制器扩展。
- 行动
 - 动态组件
 - IdeaStandardController(理念标准控制器)
 - IdeaStandardSet控制器
 - KnowledgeArticleVersionStandardController
 - 消息
 - 页面参考
 - 选择选项
 - 标准控制器
 - 标准集控制器
 
除了这些类之外,在控制器和控制器扩展中声明方法时还可以使用关键字。为 更多信息,请参阅使用 瞬态关键字。transient
有关 Visualforce 的更多信息,请参阅 Visualforce 开发人员的 指南。
JavaScript 远程处理
在 Visualforce 中使用 JavaScript 远程处理从 JavaScript的。创建具有复杂动态行为的页面,这是 标准 Visualforce AJAX 组件。使用 JavaScript 远程处理实现的功能需要三个元素:
- 您添加到 Visualforce 页面的远程方法调用,写在 JavaScript的。
 - Apex 控制器类中的远程方法定义。此方法 定义是用 Apex 编写的,但与 正常操作方法。
 - 您添加到或包含在 Visualforce 中的响应处理程序回调函数 页面,用 JavaScript 编写。
 
在控制器中,Apex 方法声明前面带有类似 这:
@RemoteAction
@RemoteAction
global static String getItemId(String objectName) { ... }
Apex 方法必须是 和 或 。
@RemoteActionstaticglobalpublic将 Apex 类作为自定义控制器或控制器扩展添加到 页。
<apex:page controller="MyController" extension="MyExtension">
警告
添加控制器或控制器扩展将授予对该 Apex 类中所有方法的访问权限, 即使页面中未使用这些方法。任何可以查看该页面的人都可以 执行所有方法并提供 向控制器发送虚假或恶意数据。@RemoteAction@RemoteAction然后,将请求添加为 JavaScript 函数调用。一个简单的 JavaScript 远程调用需要以下操作 形式。
[namespace.]MyController.method(
    [parameters...,]
    callbackFunction,
    [configuration]
);
| 元素 | 描述 | 
|---|---|
| namespace | 控制器类的命名空间。namespace 元素是 如果您的组织定义了命名空间,或者如果 类来自已安装的包。 | 
| MyController,MyExtension | Apex 控制器或扩展的名称。 | 
| method | 要调用的 Apex 方法的名称。 | 
| parameters | 方法的参数的逗号分隔列表 需要。 | 
| callbackFunction | 处理响应的 JavaScript 函数的名称 从控制器。您还可以声明匿名函数 内嵌。 接收方法调用的状态和结果 参数。callbackFunction | 
| configuration | 配置远程呼叫和响应的处理。使用这个 元素来更改远程处理调用的行为,例如是否 或者不转义 Apex 方法的响应。 | 
有关更多信息,请参阅《Visualforce 开发人员指南》中的适用于 Apex 控制器的 JavaScript 远程处理。
AJAX 中的 Apex
AJAX 工具包包括对通过匿名块调用 Apex 的内置支持 或公共方法。
webservice
要通过匿名块或公共方法调用 Apex,请在 AJAX 代码中包含以下行:webservice
<script src="/soap/ajax/59.0/connection.js" type="text/javascript"></script>
<script src="/soap/ajax/59.0/apex.js" type="text/javascript"></script>
注意
对于 AJAX 按钮,请使用这些包含的替代形式。若要调用 Apex,请使用以下两种方法之一:
- 通过匿名执行。这 方法返回的结果类似于 API 的结果类型,但作为 JavaScript 结构。sforce.apex.executeAnonymous (script)
 - 使用类 WSDL。例如,您可以调用以下 Apex 类:
global class myClass { webservice static Id makeContact(String lastName, Account a) { Contact c = new Contact(LastName = lastName, AccountId = a.Id); return c.id; } }通过使用以下 JavaScript 法典:var account = sforce.sObject("Account"); var id = sforce.apex.execute("myClass","makeContact", {lastName:"Smith", a:account});该方法采用原始数据 类型、sObject 和基元或 sObject 列表。execute要调用 不带参数的 webservice 方法,用作 的第三个参数。例如,调用以下 Apex 类:{}sforce.apex.executeglobal class myClass{ webservice static String getContextUserName() { return UserInfo.getFirstName(); } }使用以下 JavaScript 法典:var contextUser = sforce.apex.execute("myClass", "getContextUserName", {});注意如果已为您的 组织,则在调用 类。例如,要调用类, 上面的 JavaScript 代码将被重写为 遵循:myClassvar contextUser = sforce.apex.execute("myNamespace.myClass", "getContextUserName", {});若要验证组织是否具有命名空间,请记录 在您的 Salesforce 组织中,然后从“设置”中输入“快速” “查找”框,然后选择“包”。如果 命名空间已定义,它列在“开发人员”下 设置。Packages有关返回数据类型的详细信息,请参阅 AJAX 中的数据类型 工具箱 
使用以下行显示包含调试信息的窗口:
sforce.debug.trace=true;
	