Apex 电子邮件服务

您可以使用电子邮件服务来处理 入站电子邮件。例如,您可以创建自动创建的电子邮件服务 基于邮件中的联系人信息的联系人记录。您可以将每个电子邮件服务与一个或多个 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,MyExtensionApex 控制器或扩展的名称。
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;

ref