<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Rohan Mehta</title>
    <description>The latest articles on DEV Community by Rohan Mehta (@rohanmehta).</description>
    <link>https://dev.to/rohanmehta</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4145673%2Febf1b610-27af-428b-b392-ed8ac7cbbc0b.png</url>
      <title>DEV Community: Rohan Mehta</title>
      <link>https://dev.to/rohanmehta</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rohanmehta"/>
    <language>en</language>
    <item>
      <title>Salesforce Winter '26: Admin Updates That Take the Friction Out of Daily Work</title>
      <dc:creator>Rohan Mehta</dc:creator>
      <pubDate>Sat, 17 Oct 2026 13:21:17 +0000</pubDate>
      <link>https://dev.to/rohanmehta/salesforce-winter-26-admin-updates-that-take-the-friction-out-of-daily-work-3a8l</link>
      <guid>https://dev.to/rohanmehta/salesforce-winter-26-admin-updates-that-take-the-friction-out-of-daily-work-3a8l</guid>
      <description>&lt;p&gt;Salesforce releases arrive three times a year, and honestly, most of them blur together. Winter '26 is worth a closer look — not because it introduces flashy net-new products, but because it sands down the rough edges of the tools admins touch every single day: list views, reports, dashboards, and Flow Builder.&lt;/p&gt;

&lt;p&gt;I went through the release notes and picked out the updates I think will matter most in real admin life. You can also read the full breakdown in the original Way2Force article: &lt;a href="https://way2force.com/salesforce-winter-26-admin-updates/" rel="noopener noreferrer"&gt;What Salesforce Winter '26 Brings for Admins: Top Updates&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sort list views by up to five columns
&lt;/h2&gt;

&lt;p&gt;List views finally support multi-column sorting. You can now order records by up to five fields at once, each ascending or descending — cases by Contact Name, then Priority, then Date/Time Opened, for example, or opportunities by Close Date and then Amount.&lt;/p&gt;

&lt;p&gt;To set it up, open a list view's controls and choose up to five fields with a direction for each. The custom sort stays put until you change or clear it. To go back to the default, use List View Controls → Reset Column Sorting, or click a column header that isn't part of your current sort.&lt;/p&gt;

&lt;h2&gt;
  
  
  Find list-view fields with type-ahead search
&lt;/h2&gt;

&lt;p&gt;Anyone who has scrolled through an endless field list while configuring a list view will appreciate this one. Field pickers now support type-ahead search: type a character to jump to the first matching field, type it again to keep moving down the list, and press Ctrl+Space to select the focused field. It works in Lightning Experience across all editions and supports every language Salesforce supports.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let generative AI power Flow decisions
&lt;/h2&gt;

&lt;p&gt;Decision elements in flows can now analyze unstructured data with generative AI. Instead of writing brittle rules for every scenario, a customer-service flow can have AI read an incoming email, gauge its tone or urgency, and route it down the right path. This is available in Lightning Experience for Enterprise, Performance, and Unlimited editions with the Einstein add-on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use newly created records immediately in flows
&lt;/h2&gt;

&lt;p&gt;A small but mighty change: when a flow creates a record, you can now reference that record's fields directly in later elements — no extra Get Records element required. Flows get simpler and leaner. It works in Lightning Experience and Salesforce Classic, in all editions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Draft flows with Einstein Next Generation (Beta)
&lt;/h2&gt;

&lt;p&gt;Einstein Next Generation turns a plain-language description of your business requirement into a draft flow. It's available broadly in Lightning Experience, but as a Beta it's covered by Salesforce's Beta Services terms — and generating drafts consumes Einstein Request credits, the standard usage metric for generative features.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trigger flows when files are attached to records
&lt;/h2&gt;

&lt;p&gt;You can now fire a flow automatically when a file gets attached to a record. Build an Automation event-triggered flow; in the Start element, open the Event Library, choose the File Attach event, and set your entry conditions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Debug flows with a resizable side panel
&lt;/h2&gt;

&lt;p&gt;Flow Builder's debugger gets a resizable side panel, and debug results now appear as cards. Each card has a dropdown menu that jumps you straight to the relevant element on the canvas via "View on Canvas." Use the Setup tab to configure debug options and the Details tab to inspect inputs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compare flow versions side by side
&lt;/h2&gt;

&lt;p&gt;Ever wondered exactly what changed between two versions of a flow? You can now compare versions directly in Flow Builder — from the Automation app's list view or the flow's detail page, via the actions menu → Compare Versions. The comparison shows the total number of changes by type, the API names of updated elements and resources, and the details of each change. It works with autolaunched, scheduled, platform event-triggered, and record-triggered flows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Translate report and dashboard labels
&lt;/h2&gt;

&lt;p&gt;Reports and dashboards can now be localized: translate metadata labels such as Name and Description, plus dashboard widget titles, subtitles, and footers. Setup runs through Translation Workbench — enable it, add languages, assign translators, then choose your component and aspect and add the translation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Block formulas in exported reports (Beta)
&lt;/h2&gt;

&lt;p&gt;A quiet security win: admins can stop spreadsheet programs from interpreting exported field values as formulas. Enable it under Reports and Dashboards Settings, and add any extra trigger characters (comma-separated) that should be flagged at the start of field values.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add reference lines to Lightning dashboard charts (Preview)
&lt;/h2&gt;

&lt;p&gt;Reference lines — previously available only in report charts — are coming to Lightning dashboard charts. A sales manager could drop a monthly revenue target line onto a bar chart and check progress at a glance. Add a chart widget, select Show Reference Line, enter the reference value, and save the dashboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try them in a sandbox first
&lt;/h2&gt;

&lt;p&gt;Winter '26 is packed with quality-of-life wins. Review the ones that touch your org's processes in a sandbox first, then share the most useful with your stakeholders before they land in production.&lt;/p&gt;

&lt;p&gt;Originally published at &lt;a href="https://way2force.com/salesforce-winter-26-admin-updates/" rel="noopener noreferrer"&gt;Way2Force&lt;/a&gt;&lt;/p&gt;

</description>
      <category>salesforce</category>
      <category>winter26</category>
      <category>salesforceadmin</category>
      <category>flow</category>
    </item>
    <item>
      <title>Stop Unwanted Emails from Leaving Salesforce: Blocking Addresses in Email-to-Case</title>
      <dc:creator>Rohan Mehta</dc:creator>
      <pubDate>Sat, 17 Oct 2026 02:33:37 +0000</pubDate>
      <link>https://dev.to/rohanmehta/stop-unwanted-emails-from-leaving-salesforce-blocking-addresses-in-email-to-case-2m6b</link>
      <guid>https://dev.to/rohanmehta/stop-unwanted-emails-from-leaving-salesforce-blocking-addresses-in-email-to-case-2m6b</guid>
      <description>&lt;h1&gt;
  
  
  Stop Unwanted Emails from Leaving Salesforce: Blocking Addresses in Email-to-Case
&lt;/h1&gt;

&lt;p&gt;Email-to-Case is one of Service Cloud's most useful channels — and one of the easiest to misfire. An agent hits reply-all on a case thread, and suddenly your response is bouncing around an internal distribution list, a vendor's legacy inbox, or an address that auto-replies and reopens the case in an infinite loop. Everyone who runs Email-to-Case has a story like this.&lt;/p&gt;

&lt;p&gt;The usual quick fix is to hardcode blocked addresses into a validation rule or directly in Apex. It works for a week. Then a new address needs blocking, and someone has to edit code, run tests, and deploy. There's a cleaner pattern: keep the blocked list in a Custom Metadata Type and enforce it with a trigger. Admins can update the list; developers never touch the logic again.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pattern in brief
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;Custom Metadata Type&lt;/strong&gt; (CMDT) acts as a configuration table that ships with your org's metadata but can be edited in Setup without a deployment. For this use case, one text field is enough:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CMDT label: Blocked Email Address&lt;/li&gt;
&lt;li&gt;Developer name: &lt;code&gt;Blocked_Email_Address__mdt&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Field: &lt;code&gt;Email_Address__c&lt;/code&gt; (Text, required)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each record holds one address you never want agents emailing: &lt;code&gt;no-reply@yourdomain.com&lt;/code&gt;, a decommissioned vendor inbox, the monitoring mailbox that replies to everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  The enforcement: an Apex trigger on EmailMessage
&lt;/h2&gt;

&lt;p&gt;The blocking happens in a &lt;code&gt;before insert&lt;/code&gt; trigger on the &lt;code&gt;EmailMessage&lt;/code&gt; object. Before any outbound email is committed, the handler loads the blocked list from CMDT and checks the To and CC fields. If either contains a restricted address, the email gets an &lt;code&gt;addError&lt;/code&gt; and never sends.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight apex"&gt;&lt;code&gt;&lt;span class="n"&gt;trigger&lt;/span&gt; &lt;span class="n"&gt;EmailMessageTrigger&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;EmailMessage&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="k"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Trigger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;isBefore&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;Trigger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;isInsert&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;EmailMessageTriggerHandler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handleBeforeInsert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Trigger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;new&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight apex"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailMessageTriggerHandler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;handleBeforeInsert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;EmailMessage&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;emailMessageList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Load blocked addresses from Custom Metadata&lt;/span&gt;
        &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;blockedEmails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Blocked_Email_Address__mdt&lt;/span&gt; &lt;span class="n"&gt;meta&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;
             &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;Email_Address__c&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Blocked_Email_Address__mdt&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Email_Address__c&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;blockedEmails&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Email_Address__c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EmailMessage&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;emailMessageList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Outbound emails related to a Case (prefix 500) only&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Incoming&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ParentId&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
                &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;valueOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ParentId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s2"&gt;500'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;toAddr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ToAddress&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
                    &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ToAddress&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s2"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;ccAddr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;CcAddress&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
                    &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;CcAddress&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s2"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;blocked&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;blockedEmails&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;toAddr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blocked&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;ccAddr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blocked&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s2"&gt;Email not allowed to be sent to or CC&lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;&lt;span class="s2"&gt;d '&lt;/span&gt;
                            &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s2"&gt;to restricted address: '&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;blocked&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few design notes worth stealing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Only outbound emails&lt;/strong&gt; (&lt;code&gt;!email.Incoming&lt;/code&gt;) get checked — inbound messages still create cases normally.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Only case-related emails&lt;/strong&gt; (the &lt;code&gt;500&lt;/code&gt; prefix check on &lt;code&gt;ParentId&lt;/code&gt;) are filtered, so the same pattern can't accidentally break other email automation in the org.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Case-insensitive matching&lt;/strong&gt; avoids the classic &lt;code&gt;No-Reply@&lt;/code&gt; vs &lt;code&gt;no-reply@&lt;/code&gt; bypass.&lt;/li&gt;
&lt;li&gt;Keep the logic in a handler class rather than the trigger body, so it slots into an existing trigger framework.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setting it up
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create the CMDT&lt;/strong&gt; in Setup → Custom Metadata Types, with the &lt;code&gt;Email_Address__c&lt;/code&gt; text field.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add records&lt;/strong&gt; under Manage Records — one per address to block. This is the part your admins own going forward.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy the trigger + handler&lt;/strong&gt; once. After that, blocking a new address is a five-second Setup task, not a deployment.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Why this pattern is worth adopting
&lt;/h2&gt;

&lt;p&gt;It's &lt;strong&gt;dynamic&lt;/strong&gt; — the list changes without code changes. It's &lt;strong&gt;secure&lt;/strong&gt; — enforcement happens at the platform level before the email exists, so no flow or agent action can dodge it. And it's &lt;strong&gt;reusable&lt;/strong&gt; — the same CMDT-driven approach works for any metadata-flavored rule: branding injection, routing overrides, feature flags.&lt;/p&gt;

&lt;p&gt;If your org runs Email-to-Case, this is one of those small builds that prevents exactly one catastrophic "oops" email — and that's worth the afternoon.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://way2force.com/block-email-addresses-in-email-to-case-in-salesforce/" rel="noopener noreferrer"&gt;Way2Force&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>salesforce</category>
      <category>apex</category>
      <category>servicecloud</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>5 Websites Every Salesforce Professional Should Bookmark in 2026</title>
      <dc:creator>Rohan Mehta</dc:creator>
      <pubDate>Thu, 15 Oct 2026 11:42:10 +0000</pubDate>
      <link>https://dev.to/rohanmehta/5-websites-every-salesforce-professional-should-bookmark-in-2026-12gi</link>
      <guid>https://dev.to/rohanmehta/5-websites-every-salesforce-professional-should-bookmark-in-2026-12gi</guid>
      <description>&lt;p&gt;When I first joined the Salesforce world, my browser's bookmarks bar looked like a junk drawer. I had saved dozens of links — blog posts, help articles, forum threads — "for later," and almost never opened any of them again. That changed when a senior architect told me something I've never forgotten: you don't need more bookmarks, you need the right five.&lt;/p&gt;

&lt;p&gt;Years later, I can confirm he was right. The Salesforce professionals who keep growing — the ones who clear certifications, ship clean Flows, and stay current with three platform releases a year — tend to rely on a small, sharp set of resources. Here are the five websites I'd tell every admin, developer, and consultant to bookmark in 2026.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Trailhead: the official classroom
&lt;/h2&gt;

&lt;p&gt;No list can skip Salesforce's own learning platform, and in 2026 it's stronger than ever. Trailhead remains the fastest free route to certification prep, with Trailmixes that bundle exactly what each exam expects you to know.&lt;/p&gt;

&lt;p&gt;Hands-on tip: before every Salesforce release, work through the release-readiness module. It takes about twenty minutes and routinely saves you hours of confusion when new features land in your org. Pair modules with hands-on playgrounds instead of reading passively — the knowledge sticks because you built something.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Salesforce Ben: the ecosystem's newsroom
&lt;/h2&gt;

&lt;p&gt;If Trailhead is the classroom, Salesforce Ben is the staffroom conversation. What began as one person's blog has grown into a full publication covering certification guides, career advice, salary surveys, and release breakdowns written in plain language.&lt;/p&gt;

&lt;p&gt;Hands-on tip: skim their release summaries the week a new Salesforce release drops. You get the practical "what changes for me" view in minutes, which makes planning your org's upgrade far less painful. And if you're considering a move, their salary data and job board are worth a look.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Unofficial SF: the community toolbox
&lt;/h2&gt;

&lt;p&gt;Don't let the name fool you — this community-run collection is one of the most genuinely useful sites in the ecosystem. It's packed with tools, utilities, and guides that Salesforce doesn't ship itself but that working professionals reach for constantly.&lt;/p&gt;

&lt;p&gt;Hands-on tip: spend one lunch break browsing the tool collection. You'll almost certainly find two or three utilities that slot directly into your daily workflow — the kind of thing that makes you wonder how you ever worked without them.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Automation Champion: the Flow encyclopedia
&lt;/h2&gt;

&lt;p&gt;Run by Salesforce MVP Rakesh Gupta, this blog is arguably the single best Flow resource on the internet. Hundreds of detailed articles, each with step-by-step screenshots walking through real automation scenarios.&lt;/p&gt;

&lt;p&gt;Hands-on tip: his guiding philosophy is "clicks before code." The next time you're tempted to write a trigger, search the site for a Flow-based approach first. You'll build faster, and your future self will thank you when the automation needs maintenance. This is the site I open most when I get stuck on a Flow requirement.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Apex Hours: the free video university
&lt;/h2&gt;

&lt;p&gt;Prefer learning by watching? Apex Hours runs free live sessions — recorded for later viewing — hosted by Amit Chaudhary and a rotating cast of community experts. Apex, Lightning Web Components, integrations, DevOps: it's all covered.&lt;/p&gt;

&lt;p&gt;Hands-on tip: treat the session recordings like a personal conference. Pick one topic a week, watch at 1.25x speed, and follow along in a scratch org. A month of this habit will move your skills further than a month of random tutorials.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't try to consume everything
&lt;/h2&gt;

&lt;p&gt;The trap is the same one I fell into at the start: bookmarking all five and trying to read every article on every site. That's how a bookmark bar becomes a junk drawer again. Instead, pick the one resource that matches what you're working on right now — certification prep, a Flow build, release readiness — and go deep there first.&lt;/p&gt;

&lt;p&gt;For a longer take on how these sites fit into a learning routine, I wrote the full version of this list over at Way2Force: &lt;a href="https://way2force.com/websites-every-salesforce-professional-should-know/" rel="noopener noreferrer"&gt;5 Websites Every Salesforce Professional Should Know in 2026&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What are your must-visit Salesforce sites? Drop them in the comments — I'm always looking to sharpen my own list.&lt;/p&gt;

&lt;p&gt;Originally published at &lt;a href="https://way2force.com/websites-every-salesforce-professional-should-know/" rel="noopener noreferrer"&gt;Way2Force&lt;/a&gt;&lt;/p&gt;

</description>
      <category>salesforce</category>
      <category>tutorial</category>
      <category>crm</category>
    </item>
    <item>
      <title>Building Customer Portals Without Experience Cloud: Four Alternatives Worth Knowing</title>
      <dc:creator>Rohan Mehta</dc:creator>
      <pubDate>Wed, 14 Oct 2026 12:47:20 +0000</pubDate>
      <link>https://dev.to/rohanmehta/building-customer-portals-without-experience-cloud-four-alternatives-worth-knowing-4k4i</link>
      <guid>https://dev.to/rohanmehta/building-customer-portals-without-experience-cloud-four-alternatives-worth-knowing-4k4i</guid>
      <description>&lt;p&gt;When Salesforce admins hear "customer portal," most of us picture Experience Cloud first. It is the native answer: customers sign in to a branded site, open their own cases, and read Knowledge articles, all against your live org data.&lt;/p&gt;

&lt;p&gt;But the native answer is not always the right answer for every team. Licensing costs, admin capacity, design freedom, or a business unit that already runs on another stack can all push you to look elsewhere. The trouble is that most roundups of Experience Cloud replacements read like feature bingo, and almost every product ticks almost every box.&lt;/p&gt;

&lt;p&gt;There is a better way to judge them. Instead of comparing features, ask two questions that sit underneath the whole decision: where does the portal keep customer data, and what are portal customers in Salesforce's eyes? Those two answers decide what you pay Salesforce and how the whole thing behaves when it breaks. I first mapped this out in the &lt;a href="https://way2force.com/salesforce-experience-cloud-alternatives-for-building-customer-portals/" rel="noopener noreferrer"&gt;original long-form piece at Way2Force&lt;/a&gt;, and this post is the condensed, hands-on version for admins and developers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four places a portal can live
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. On the platform: Experience Cloud and its ecosystem
&lt;/h3&gt;

&lt;p&gt;This is the starting point rather than a true alternative. Every customer is a licensed external user: Customer Community for high-volume self-service, Customer Community Plus when you need roles and sharing rules, Partner Community for channel users with leads and opportunities, plus a few narrower license types for edge cases.&lt;/p&gt;

&lt;p&gt;Some tools that appear on "alternatives" lists actually live here. Advanced Communities adds components on top of Experience Cloud and still requires an Experience Cloud license. There is also a headless flavor: your own React or mobile front end that signs customers in through Salesforce's headless identity APIs, keeping them licensed external users governed by the sharing model.&lt;/p&gt;

&lt;p&gt;Why teams stay: there is no second copy of anything. When an agent closes a case at 4:55 p.m., the portal shows it closed at 4:55 p.m., because it is the same record. Security is enforced by the platform itself, so profiles, permission sets, sharing rules, login history, and Shield event monitoring (if you own it) cover external users too. Knowledge articles and Service Cloud cases work against live data from day one, and newer Agentforce self-service components slot straight into the site.&lt;/p&gt;

&lt;p&gt;The price you pay: every customer needs a license, and every configuration change needs Salesforce skills. Guest access deserves particular respect, because researchers have repeatedly found Experience Cloud sites exposing private records to anonymous visitors through overly generous guest permissions. Salesforce has tightened the defaults since — guest users now receive records only through read-only guest sharing rules, and the external org-wide default for guests is forced to Private. Those protections help, but the platform enforces the design you build, not the design you meant.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Off-platform with a live connection
&lt;/h3&gt;

&lt;p&gt;These portals live outside Salesforce and read and write your org's records on demand through a connected app, keeping no copy of their own. CRMJetty is one example of this pattern. Salesforce stays the system of record, portal users do not consume Salesforce licenses, and the site can be configured without touching Experience Builder.&lt;/p&gt;

&lt;p&gt;The big bill here is the API budget. An Enterprise org gets 100,000 API calls per rolling 24 hours plus 1,000 per full Salesforce or Salesforce Platform license; Customer Community Plus and Partner Community add 200 each, while plain Customer Community adds nothing. Do the rough math: 1,000 customers loading ten pages a day at three calls a page is 30,000 calls — drawn from the same pool your other integrations drink from. Ask every vendor how many calls a typical page costs and whether it caches.&lt;/p&gt;

&lt;p&gt;Then there is connection security. In August 2025, attackers used OAuth tokens stolen from the Salesloft Drift integration to export data from Salesforce instances at more than 700 organizations, according to Google's threat-intelligence team. Nobody broke into Salesforce; they rode a trusted connection. So ask what permissions the integration user holds, where tokens are stored, how you would revoke them in an emergency, and whether the connected app is installed in your org — since September 2025, Salesforce blocks most users from authorizing uninstalled connected apps.&lt;/p&gt;

&lt;p&gt;One more subtlety: visibility rules live in the vendor's layer here, because customers are not Salesforce users. Your access-control review must cover the portal's configuration, not just your org's. Test it like an attacker would: sign in as one customer and try to open another customer's record by changing an ID in the URL.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Off-platform with a synced copy
&lt;/h3&gt;

&lt;p&gt;These products keep their own database and refresh it from Salesforce on a schedule. Magentrix mirrors CRM records into its own platform, no-code builders like Knack run on their own database, and community platforms like Higher Logic Vanilla sync through a connector or Zapier.&lt;/p&gt;

&lt;p&gt;The appeal: pages load from local data, the portal keeps working through a Salesforce outage, and page views do not spend your API budget. The costs: freshness — a few hours of lag is invisible on a knowledge base and unacceptable on case or order status, so ask for the sync interval per object, not as a headline number. Writes can collide when a customer and an agent edit the same record at once, so ask which edit wins and who gets told. And every mirrored record is a second copy of customer data that you must secure, retain, and delete when asked.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. A different system of record entirely
&lt;/h3&gt;

&lt;p&gt;Microsoft Power Pages, for example, builds portals on Dataverse — Microsoft's data platform, not Salesforce. This only belongs on the shortlist if you are moving customer data off Salesforce or part of the business already runs on Dynamics 365. Otherwise you are adopting a whole second platform, and the portal is the smallest part of that decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  Five questions that place any vendor on the map
&lt;/h2&gt;

&lt;p&gt;Before the feature grid, put these to every option, including Experience Cloud:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;After a customer views a record, where does it live — your org only, the vendor's database, or both?&lt;/li&gt;
&lt;li&gt;Who is the customer in Salesforce's eyes — a licensed external user, or someone represented by an integration user?&lt;/li&gt;
&lt;li&gt;What enforces record visibility — the Salesforce sharing model, or the vendor's access layer? If the vendor's, ask to see the configuration and the testing.&lt;/li&gt;
&lt;li&gt;What does a typical page cost in API calls — or how stale can the data get? Every off-platform option spends one or the other.&lt;/li&gt;
&lt;li&gt;What happens when the connection fails, and how do you revoke it? Walk through planned Salesforce maintenance and an expired token first.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These answers narrow a long shortlist to two or three serious contenders faster than any comparison table.&lt;/p&gt;

&lt;h2&gt;
  
  
  The short version
&lt;/h2&gt;

&lt;p&gt;Experience Cloud is the only option where the portal and the CRM are literally the same system, and for teams with in-house Salesforce skills that is often the deciding advantage. Alternatives do not erase the work Experience Cloud does — they relocate it. A live connection shifts it to API budgeting and connection security; a synced copy shifts it to reconciliation and data governance. Choose the architecture whose chores your team is best equipped to handle, then compare features inside that lane.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: this post adapts the original Way2Force piece, which disclosed the author's affiliation with one of the vendors named above. The architectures and questions here are meant to be applied to every option on a shortlist, including that one.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Originally published at &lt;a href="https://way2force.com/salesforce-experience-cloud-alternatives-for-building-customer-portals/" rel="noopener noreferrer"&gt;Way2Force&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>salesforce</category>
      <category>tutorial</category>
      <category>crm</category>
    </item>
    <item>
      <title>Why Every AI Strategy Needs Data Cleaning First</title>
      <dc:creator>Rohan Mehta</dc:creator>
      <pubDate>Tue, 13 Oct 2026 11:42:12 +0000</pubDate>
      <link>https://dev.to/rohanmehta/why-every-ai-strategy-needs-data-cleaning-first-20c2</link>
      <guid>https://dev.to/rohanmehta/why-every-ai-strategy-needs-data-cleaning-first-20c2</guid>
      <description>&lt;p&gt;Everyone wants AI. Salesforce admins get asked about Agentforce pilots, execs want predictive dashboards, and every vendor demo promises magic. But here's the uncomfortable truth I keep seeing in Salesforce orgs: AI fails on dirty data. Not sometimes — almost every time.&lt;/p&gt;

&lt;p&gt;Large language models and predictive engines are pattern matchers. Feed them duplicate leads, half-empty account records, and five different spellings of the same company name, and they will confidently generate nonsense. Garbage in doesn't just mean garbage out anymore — it means garbage at scale, delivered with machine confidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dirty data is an AI problem, not a housekeeping problem
&lt;/h2&gt;

&lt;p&gt;In most Salesforce orgs I've worked with, the data issues are depressingly familiar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Duplicate contacts and leads from years of web-to-lead forms and sloppy imports&lt;/li&gt;
&lt;li&gt;Fields that look required but sit empty on half your records&lt;/li&gt;
&lt;li&gt;"Closed Won" opportunities with no amount, no close date, and no products&lt;/li&gt;
&lt;li&gt;Picklist values like "N/A", "n/a", "NA", and "Not Applicable" living side by side&lt;/li&gt;
&lt;li&gt;Stale records for people who left their companies three years ago&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An AI assistant trained on this mess will route cases to dead email addresses, score leads on fictional data, and summarize accounts with phantom revenue. Your users won't blame the data — they'll blame the AI, and adoption dies before it starts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with a data audit, not a model
&lt;/h2&gt;

&lt;p&gt;Before you greenlight any AI project, run a proper audit of the objects your AI will touch. Pull reports on empty key fields, run duplicate jobs, and sample records manually. You can't fix what you haven't measured — and a one-page "data health" summary is the most persuasive document you can put in front of leadership. I walk through this full process in &lt;a href="https://way2force.com/ai-strategy-needs-data-cleaning/" rel="noopener noreferrer"&gt;Why Every AI Strategy Needs Data Cleaning First&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Clean in this order
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Deduplicate.&lt;/strong&gt; Merge duplicate accounts, contacts, and leads first — duplicates multiply every other problem downstream.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Complete the critical fields.&lt;/strong&gt; Identify the 10–15 fields your AI actually needs (email, phone, industry, stage, amount) and get them reliably populated.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Standardize formats.&lt;/strong&gt; Phone numbers, addresses, picklist values — pick one format and enforce it with validation rules.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Delete or archive the dead weight.&lt;/strong&gt; Records untouched in years with zero engagement are noise. Archive them so they stop polluting your models.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Fix it at the source.&lt;/strong&gt; Validation rules, required fields on page layouts, duplicate rules, and Flow-based enrichment stop bad data from re-entering the org.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make cleanliness automatic
&lt;/h2&gt;

&lt;p&gt;One-time cleanup projects fail because data decays. Set up scheduled duplicate jobs, exception reports emailed to record owners weekly, and a simple dashboard tracking data completeness over time. Assign real data ownership — every object should have someone accountable. This is the unglamorous operational layer that makes AI actually work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Then — and only then — bring in AI
&lt;/h2&gt;

&lt;p&gt;Once your data is trustworthy, Salesforce's AI features start earning their keep: lead scoring that reflects reality, case classification that routes correctly, summaries grounded in actual history. The teams that succeed with AI aren't the ones with the fanciest models; they're the ones whose data the model can trust.&lt;/p&gt;

&lt;p&gt;Clean data isn't the boring prerequisite to your AI strategy. It &lt;em&gt;is&lt;/em&gt; the AI strategy. Everything else is decoration.&lt;/p&gt;




&lt;p&gt;Originally published at &lt;a href="https://way2force.com/ai-strategy-needs-data-cleaning/" rel="noopener noreferrer"&gt;Way2Force&lt;/a&gt;&lt;/p&gt;

</description>
      <category>salesforce</category>
      <category>ai</category>
      <category>data</category>
      <category>automation</category>
    </item>
    <item>
      <title>Apex Test Coverage in 2026: Rules, Gotchas, and How to Write Tests That Actually Help</title>
      <dc:creator>Rohan Mehta</dc:creator>
      <pubDate>Mon, 12 Oct 2026 11:45:13 +0000</pubDate>
      <link>https://dev.to/rohanmehta/apex-test-coverage-in-2026-rules-gotchas-and-how-to-write-tests-that-actually-help-11dl</link>
      <guid>https://dev.to/rohanmehta/apex-test-coverage-in-2026-rules-gotchas-and-how-to-write-tests-that-actually-help-11dl</guid>
      <description>&lt;p&gt;If you've ever tried to push Apex code to a production org, you've met Salesforce's deployment gatekeeper: the mandatory test run. In 2026, those rules haven't relaxed at all — and that's deliberate. Tests aren't bureaucracy; they're how a shared, multi-tenant platform stays trustworthy when thousands of developers ship code every day.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Salesforce enforces test coverage
&lt;/h2&gt;

&lt;p&gt;Salesforce executes your code alongside everyone else's in a multi-tenant architecture. A careless trigger on your org can't be allowed to undermine the platform's reliability for your users. Mandatory tests serve two purposes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Deployment safety.&lt;/strong&gt; Production deployments require a passing test run. If your tests fail, your metadata stays in the sandbox. Simple as that.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regression insurance.&lt;/strong&gt; Orgs evolve constantly — admins add flows, validation rules, and required fields. A solid test suite catches the breakage before your users do.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The coverage rules, precisely
&lt;/h2&gt;

&lt;p&gt;Here is what the platform actually demands before a production deployment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;At least 75% of all Apex code&lt;/strong&gt; in the org must be executed by tests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Every trigger must have some coverage&lt;/strong&gt; — an untested trigger blocks deployment even if the org-wide number looks fine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;All test methods must pass.&lt;/strong&gt; No failures, no uncaught exceptions.&lt;/li&gt;
&lt;li&gt;Test classes themselves don't count toward the 75%.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notice what's missing from that list: any requirement that your tests be &lt;em&gt;good&lt;/em&gt;. A test that executes code without asserting anything still inflates the percentage. Which brings us to the real problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stop gaming coverage; start asserting
&lt;/h2&gt;

&lt;p&gt;Coverage is a floor, not a finish line. A test without &lt;code&gt;System.assert&lt;/code&gt; calls proves nothing except that your code doesn't crash on one narrow path. Meaningful tests assert outcomes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Assert the &lt;strong&gt;business result&lt;/strong&gt;, not the implementation detail. ("The opportunity moved to Closed Won" beats "the method returned true.")&lt;/li&gt;
&lt;li&gt;Test the unhappy paths: validation failures, null inputs, and governor-limit-adjacent bulk sizes.&lt;/li&gt;
&lt;li&gt;Cover every branch of your conditionals — both sides of each &lt;code&gt;if/else&lt;/code&gt; and every ternary outcome.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Write tests you'd trust to run at 2 AM during a release window. We walk through the full setup in our &lt;a href="https://way2force.com/salesforce-test-classes/" rel="noopener noreferrer"&gt;test classes and code coverage guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bulk-safe test data patterns
&lt;/h2&gt;

&lt;p&gt;Tests that insert a single record and call it a day are lying to you. Real orgs process data in bulk — triggers fire on up to 200 records at a time. Build that reality into your tests from the start:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Create your own data.&lt;/strong&gt; Never depend on existing org data (&lt;code&gt;SeeAllData=true&lt;/code&gt; is a trap that makes tests fail in fresh sandboxes). Generate records that mirror real business scenarios, including related records.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use &lt;code&gt;@TestSetup&lt;/code&gt;.&lt;/strong&gt; One setup method builds shared data once per test class, keeping tests fast and consistent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Centralize with a Test Data Factory.&lt;/strong&gt; A single utility class that produces Accounts, Contacts, and Opportunities with sensible defaults saves everyone on the team from reinventing fixtures.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test in bulk.&lt;/strong&gt; Insert 200 records, not one. That's where SOQL-in-loop bugs and governor-limit failures hide.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight apex"&gt;&lt;code&gt;&lt;span class="nd"&gt;@isTest&lt;/span&gt;
&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AccountTriggerTest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@TestSetup&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;makeData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Account&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;accts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Account&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;accts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Account&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s2"&gt;Test '&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;insert&lt;/span&gt; &lt;span class="n"&gt;accts&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@isTest&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;bulkInsertSetsIndustry&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startTest&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="c1"&gt;// trigger logic under test runs against the @TestSetup data&lt;/span&gt;
        &lt;span class="n"&gt;Test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stopTest&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="n"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;flagged&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="nf"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Account&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;Industry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s2"&gt;Technology'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flagged&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s2"&gt;All bulk-inserted accounts should be flagged'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Test.startTest()&lt;/code&gt; and &lt;code&gt;Test.stopTest()&lt;/code&gt; also reset governor limits and force asynchronous code — future methods, queueables, batch jobs — to run synchronously, which is essential for testing anything &lt;code&gt;@future&lt;/code&gt; or scheduled.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deployment gotchas that still bite in 2026
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Coverage evaporates on edit.&lt;/strong&gt; The moment you modify a class, its coverage data is cleared until tests run again. Re-run after every change.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mixed DML errors.&lt;/strong&gt; Creating a User and an Account in the same transaction blows up. Wrap user-context setup in &lt;code&gt;System.runAs()&lt;/code&gt;, which also lets you verify sharing rules and profile behavior.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run test classes individually when debugging.&lt;/strong&gt; One class at a time makes failures far easier to isolate than a full-org run.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Aim above the minimum.&lt;/strong&gt; 75% gets you deployed; targeting 90% or more across classes and triggers gives you headroom for the inevitable coverage dip when someone edits a class the night before a release.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Good tests are documentation that executes. They tell the next developer what the code is &lt;em&gt;supposed&lt;/em&gt; to do — and they scream when it stops doing it. Write them like the next person reading them is you, six months from now, during an incident.&lt;/p&gt;

&lt;p&gt;Originally published at &lt;a href="https://way2force.com/salesforce-test-classes/" rel="noopener noreferrer"&gt;Way2Force&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>salesforce</category>
      <category>tutorial</category>
      <category>testing</category>
      <category>apex</category>
    </item>
    <item>
      <title>Stop Manually Removing Salesforce Permissions: Assign Permission Sets That Expire on Their Own</title>
      <dc:creator>Rohan Mehta</dc:creator>
      <pubDate>Sun, 11 Oct 2026 11:42:20 +0000</pubDate>
      <link>https://dev.to/rohanmehta/stop-manually-removing-salesforce-permissions-assign-permission-sets-that-expire-on-their-own-12db</link>
      <guid>https://dev.to/rohanmehta/stop-manually-removing-salesforce-permissions-assign-permission-sets-that-expire-on-their-own-12db</guid>
      <description>&lt;h1&gt;
  
  
  Stop Manually Removing Salesforce Permissions: Assign Permission Sets That Expire on Their Own
&lt;/h1&gt;

&lt;p&gt;Every Salesforce admin has the same recurring chore: granting temporary access and then remembering to take it away. A contractor needs elevated access for two weeks. A support rep covers a queue for a month. A developer needs production data access until go-live. You grant the permission set, make a mental note to revoke it later — and later never comes.&lt;/p&gt;

&lt;p&gt;Permission sets with an expiration date fix this at the source. Instead of remembering to remove access, you set the end date when you grant it. Salesforce handles the rest.&lt;/p&gt;

&lt;h2&gt;
  
  
  How assignment expiration works
&lt;/h2&gt;

&lt;p&gt;When you assign a permission set to a user, you can now choose an expiration date for that assignment. On that date, the assignment is removed automatically — no manual cleanup, no audit scramble.&lt;/p&gt;

&lt;p&gt;The mechanics are straightforward:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;Setup → Permission Sets&lt;/strong&gt; and open the permission set you want to assign.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Manage Assignments → Add Assignments&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select the users, click &lt;strong&gt;Next&lt;/strong&gt; — and this is the step most admins miss — set the &lt;strong&gt;expiration date&lt;/strong&gt; before confirming.&lt;/li&gt;
&lt;li&gt;Alternatively, manage expirations in bulk from &lt;strong&gt;Setup → Users → Permission Set Assignments&lt;/strong&gt; using the &lt;strong&gt;Manage Assignment Expiration&lt;/strong&gt; action.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can also pick a relative window (a set number of days) instead of a fixed date, which is handy when the same temporary-access pattern repeats.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this actually pays off
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Contractors and consultants.&lt;/strong&gt; Scope their access to the engagement window. When the contract ends, the access ends — not three months later when someone finally audits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Temporary elevation.&lt;/strong&gt; Covering for a colleague on leave? Granting elevated access "until Sarah is back"? Put a date on it instead of trusting your memory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project teams.&lt;/strong&gt; Data migration, go-live support, UAT — all time-boxed by nature. Match the access window to the project window.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Compliance and reviews.&lt;/strong&gt; If your org does quarterly access reviews, expiration dates turn the review into a confirmation exercise instead of a cleanup project. Auditors love seeing access that provably lapsed on schedule.&lt;/p&gt;

&lt;h2&gt;
  
  
  A few things to watch
&lt;/h2&gt;

&lt;p&gt;Expiration removes access silently, so communicate the end date to the user — nobody enjoys discovering at 9 AM that their access evaporated overnight. For genuinely recurring temporary needs, consider automating the assignment itself with a flow so the whole lifecycle is hands-off. And note that expiration applies to the &lt;em&gt;assignment&lt;/em&gt;, not the permission set: the permission set definition stays intact and reusable.&lt;/p&gt;

&lt;p&gt;One more consideration: session-based permission sets (the old "activate for this session" model) are on their way out. Assignment expiration is the supported pattern going forward — it's worth migrating any session-based processes to it now rather than under deadline pressure.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bottom line
&lt;/h2&gt;

&lt;p&gt;Access that expires on its own is one of those small governance wins that compounds. Fewer stale assignments, cleaner audits, and one less thing living in your memory instead of the system. If you've been managing temporary access with calendar reminders, this is the week to stop.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://way2force.com/how-to-set-up-and-assign-permission-sets-with-an-expiration-date-in-salesforce/" rel="noopener noreferrer"&gt;Way2Force&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>salesforce</category>
      <category>security</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Send Custom Notifications in Salesforce Using Flow: A No-Code Guide</title>
      <dc:creator>Rohan Mehta</dc:creator>
      <pubDate>Sat, 10 Oct 2026 11:43:15 +0000</pubDate>
      <link>https://dev.to/rohanmehta/send-custom-notifications-in-salesforce-using-flow-a-no-code-guide-1547</link>
      <guid>https://dev.to/rohanmehta/send-custom-notifications-in-salesforce-using-flow-a-no-code-guide-1547</guid>
      <description>&lt;h1&gt;
  
  
  Send Custom Notifications in Salesforce Using Flow: A No-Code Guide
&lt;/h1&gt;

&lt;p&gt;Users miss things. A high-value opportunity stalls, a case sits untouched for days, an approval request goes unnoticed — not because Salesforce can't surface these moments, but because nobody thinks to look in the right place at the right time.&lt;/p&gt;

&lt;p&gt;Custom notifications fix that. They push an alert straight to the Salesforce notification bell (and the mobile app) when something important happens, and the whole thing can be built with clicks in Flow Builder — no Apex required.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you need before you start
&lt;/h2&gt;

&lt;p&gt;Two building blocks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A Custom Notification Type&lt;/strong&gt; — created once in Setup (&lt;code&gt;Notification Builder &amp;gt; Custom Notifications&lt;/code&gt;). Give it a name, set the channels (desktop, mobile, or both), and finish. This is the "envelope" your flow will use.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A Flow&lt;/strong&gt; — typically a record-triggered flow that decides &lt;em&gt;when&lt;/em&gt; the notification fires and &lt;em&gt;who&lt;/em&gt; receives it.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Building the flow
&lt;/h2&gt;

&lt;p&gt;Create a &lt;strong&gt;record-triggered flow&lt;/strong&gt; on the object you care about — Opportunity, Case, or whatever matches your use case. Set it to trigger on create or update, then add your entry criteria so it only fires when it matters (for example, an opportunity stage changing to "Negotiation" with an amount over a threshold).&lt;/p&gt;

&lt;p&gt;Next, add the &lt;strong&gt;Send Custom Notification&lt;/strong&gt; action element. This is where you wire up the pieces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Notification Type&lt;/strong&gt; — the custom notification type you created in Setup. You'll need its ID (grab it from a Get Records on the CustomNotificationType object, or reference it directly).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Title and Body&lt;/strong&gt; — build these with formula resources so the message feels personal: something like "Opportunity {Record.Name} needs attention" with the stage and amount in the body.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recipient IDs&lt;/strong&gt; — a collection variable of user IDs. Use Get Records to find the right people (opportunity owner, team members, managers) and assign their IDs into the collection.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Target ID&lt;/strong&gt; — the record the notification should deep-link to, so one click takes the user exactly where they need to act.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A practical example
&lt;/h2&gt;

&lt;p&gt;Say you want managers notified whenever a deal over $50K goes idle for more than 7 days. A scheduled-triggered flow can run daily, query opportunities that match, and send one notification per record to the owner and their manager. The recipient gets a bell notification and a mobile push with the deal name, stage, and a link straight to the record — instead of a forgotten line in a report.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tips that save you headaches
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Keep the title short.&lt;/strong&gt; The bell banner shows limited text; put the detail in the body.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mind volume.&lt;/strong&gt; Scheduled flows plus broad criteria can spam people fast. Filter aggressively, and consider batching into a summary message.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test as a non-admin.&lt;/strong&gt; Notification visibility respects sharing; verify the recipient can actually open the target record.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use mobile push for the truly urgent.&lt;/strong&gt; Bell-only notifications are cheap and quiet; save push for escalations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Custom notifications are one of those small Flow features with outsized impact: five minutes of configuration, and your team stops missing the moments that matter.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://way2force.com/how-to-send-custom-notifications-in-salesforce-using-flow/" rel="noopener noreferrer"&gt;Way2Force&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>salesforce</category>
      <category>automation</category>
      <category>tutorial</category>
      <category>lowcode</category>
    </item>
    <item>
      <title>Setting Up Slack with Salesforce: A Practical Admin Walkthrough</title>
      <dc:creator>Rohan Mehta</dc:creator>
      <pubDate>Fri, 09 Oct 2026 11:42:28 +0000</pubDate>
      <link>https://dev.to/rohanmehta/setting-up-slack-with-salesforce-a-practical-admin-walkthrough-51n3</link>
      <guid>https://dev.to/rohanmehta/setting-up-slack-with-salesforce-a-practical-admin-walkthrough-51n3</guid>
      <description>&lt;p&gt;Salesforce admins spend a big part of their week inside the CRM, but the rest of the team lives in Slack. Deal notes get discussed in channels, support escalations fly through DMs, and important updates vanish into the scroll before anyone logs them in Salesforce. Connecting Slack to Salesforce bridges that gap — conversations stay tied to records, and data stays visible where work actually happens.&lt;/p&gt;

&lt;p&gt;I recently walked through this setup in a trial org, and it turned out to be far more straightforward than I expected. Here is the path I followed, plus a few lessons learned along the way.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Connecting Slack to Salesforce with Guided Setup
&lt;/h2&gt;

&lt;p&gt;You don't need a paid add-on or custom code to get started. Salesforce ships a guided flow that handles the connection for you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open &lt;strong&gt;Setup&lt;/strong&gt; (click the gear icon) and search for &lt;strong&gt;Guided Slack Setup&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The guided page lists the steps to link a Slack workspace to your org. In many trial and scratch orgs, a Slack workspace is already provisioned, so all you do is open &lt;strong&gt;Manage Slack Connection&lt;/strong&gt; to confirm the workspace name, URL, and connection status.&lt;/li&gt;
&lt;li&gt;Click the workspace URL, sign in to Slack, and return to Salesforce.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mark each step complete in the guided page as you go — it keeps the rollout traceable if a colleague needs to replicate it later.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Bringing Slack into Record Pages and Flow
&lt;/h2&gt;

&lt;p&gt;The connection alone is only half the value. The real payoff comes from surfacing Slack where users already work:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Add the Slack component to record pages.&lt;/strong&gt; Back in Guided Slack Setup, choose &lt;em&gt;Add Slack conversations to record pages&lt;/em&gt;, pick an object (Account is the natural starting point), and open the page in Lightning App Builder. Drag the Slack component onto the layout where it will be noticed, then save and activate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test it.&lt;/strong&gt; Open an Account record, and from the Slack component you can connect or create a Slack channel tied to that Account. Messages posted from the record appear in the Slack channel, and replies in Slack flow back into the record. The conversation is anchored to the right Account, so context never gets lost.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use Slack inside Flow.&lt;/strong&gt; Admins can push notifications into Slack directly from Flow — for example, posting to a channel when an Opportunity stage changes or when a Case escalates. Pair this with the record-page component and you get a loop: alerts go out automatically, and discussion happens against the record.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let users view Salesforce data from Slack.&lt;/strong&gt; Once connected, Salesforce actions appear inside Slack. Users can look up records, view details, and — depending on permissions — update fields, with changes syncing both ways.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Practical Tips for Admins
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Check licenses and permissions first.&lt;/strong&gt; Salesforce permissions still govern what each user can see and edit. Test with a standard user profile, not just as an admin.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Start with one object.&lt;/strong&gt; Roll out on Account first, learn how your team uses it, then extend to Opportunities or Cases.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Name channels deliberately.&lt;/strong&gt; A consistent naming convention (for example, &lt;code&gt;acct-acme-corp&lt;/code&gt;) makes channels discoverable and keeps the integration tidy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Train on the two-way sync.&lt;/strong&gt; The biggest "wow" moment for users is learning that an update in Slack shows up in Salesforce — demonstrate it live in your first demo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitor adoption.&lt;/strong&gt; Watch which records get linked channels and which don't; low usage usually means the component placement or the workflow needs adjusting, not that the integration is broken.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Payoff
&lt;/h2&gt;

&lt;p&gt;The benefits show up quickly: less app switching, conversations that stay attached to the right records, faster updates from either side, and productivity gains that compound across the team. Most importantly, nothing about security changes — the same Salesforce permission model applies inside Slack.&lt;/p&gt;

&lt;p&gt;If you haven't connected the two yet, block out an afternoon and try it in a sandbox or trial org. The guided setup removes the guesswork, and your users will thank you the next time a deal discussion doesn't disappear into a Slack thread.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://way2force.com/set-up-slack-with-salesforce/" rel="noopener noreferrer"&gt;Way2Force&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>salesforce</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>ClaudeForce and Salesforce: What the Anthropic Partnership Really Means for You</title>
      <dc:creator>Rohan Mehta</dc:creator>
      <pubDate>Thu, 08 Oct 2026 11:43:15 +0000</pubDate>
      <link>https://dev.to/rohanmehta/claudeforce-and-salesforce-what-the-anthropic-partnership-really-means-for-you-3e9a</link>
      <guid>https://dev.to/rohanmehta/claudeforce-and-salesforce-what-the-anthropic-partnership-really-means-for-you-3e9a</guid>
      <description>&lt;p&gt;If your feed felt a little louder than usual earlier this year, there was a reason: Salesforce and Anthropic announced ClaudeForce, arguably the biggest AI news in the Salesforce ecosystem in 2026.&lt;/p&gt;

&lt;p&gt;I've spent years watching Salesforce roll out AI features, from Einstein Copilot to Agentforce. ClaudeForce is different. It isn't another assistant bolted onto the CRM. It's a two-way bridge: Claude can now reason over your Salesforce data, and Salesforce is available directly inside Claude. Let me unpack what it actually is, why it exists, and what it means for those of us building on the platform every day.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is ClaudeForce, Really?
&lt;/h2&gt;

&lt;p&gt;ClaudeForce is the product of Salesforce's partnership with Anthropic. At its core, it plugs Claude's reasoning into Salesforce's Customer 360 — your records, your Slack conversations, your workflows — and lets you work with all of it through natural language.&lt;/p&gt;

&lt;p&gt;Ask for a summary of an account before a meeting, and Claude pulls together the relevant records and business context instead of you clicking through five tabs. Describe a change in plain English and have the record updated. That is the promise: less hunting, more doing.&lt;/p&gt;

&lt;p&gt;Critically, ClaudeForce is not a chatbot skin, and it is not here to replace Agentforce. Salesforce kept its existing security and permission model intact, so enterprise governance travels with the data. AI gets the reasoning seat; Salesforce keeps the keys.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Salesforce Built It
&lt;/h2&gt;

&lt;p&gt;Here's the honest truth about life as a Salesforce user: you live in tab-switching purgatory. A sales rep checks opportunities in Salesforce, reads the customer thread in Slack, pulls a report, then updates the CRM by hand. Multiply that by every rep, every day, and you get an enormous amount of expensive busywork.&lt;/p&gt;

&lt;p&gt;ClaudeForce exists to collapse that context-switching. If one AI can see the CRM, the conversations, and the workflows together, the rep stops being a data courier and starts being a seller.&lt;/p&gt;

&lt;h2&gt;
  
  
  Salesforce in Claude: The First Big Experience
&lt;/h2&gt;

&lt;p&gt;The flagship experience is called Salesforce in Claude. Once an admin enables it, Salesforce data becomes available inside Claude — no custom APIs, no integration project.&lt;/p&gt;

&lt;p&gt;Salesforce shipped 37 pre-built Sales Skills with it. Think of them as ready-made superpowers for sellers: prepping for customer meetings, summarizing account history, reviewing pipeline health, flagging opportunities at risk, and updating records using natural language. A seller can ask Claude to brief them on an account, and it assembles the picture from Salesforce records and surrounding business context.&lt;/p&gt;

&lt;p&gt;Slack integration and the underlying plumbing — components Salesforce calls AIforce, Headless 360, Data 360, and MCP — round out the first release.&lt;/p&gt;

&lt;h2&gt;
  
  
  What It Means for Salesforce Professionals
&lt;/h2&gt;

&lt;p&gt;For admins, the message is: learn the enablement and governance story. Your sharing rules and permissions still apply, which means the architecture you already built continues to protect the data. ClaudeForce rewards clean data and well-designed security.&lt;/p&gt;

&lt;p&gt;For developers, ClaudeForce is a signal about where Salesforce is heading: open protocols like MCP, headless access to 360 data, and AI experiences that live where users already work. The integration surface is shifting from screens to conversations.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Practical Takeaway
&lt;/h2&gt;

&lt;p&gt;Don't wait for a mandate to start experimenting. Pick one repetitive workflow — meeting prep is the classic — and try running it through Salesforce in Claude in a sandbox or pilot org. Time how long the manual version takes today, then compare. That gap is the business case, and it's the number you'll bring to your stakeholders.&lt;/p&gt;

&lt;p&gt;The platforms we build on are changing shape. ClaudeForce won't replace good Salesforce architecture — but it will reward the teams whose data and governance are clean enough for AI to reason over.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://way2force.com/claudeforce-in-salesforce/" rel="noopener noreferrer"&gt;Way2Force&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>salesforce</category>
      <category>ai</category>
      <category>claude</category>
    </item>
    <item>
      <title>Delegate These 7 Salesforce Admin Tasks to Claude Code</title>
      <dc:creator>Rohan Mehta</dc:creator>
      <pubDate>Wed, 07 Oct 2026 11:41:43 +0000</pubDate>
      <link>https://dev.to/rohanmehta/delegate-these-7-salesforce-admin-tasks-to-claude-code-3moh</link>
      <guid>https://dev.to/rohanmehta/delegate-these-7-salesforce-admin-tasks-to-claude-code-3moh</guid>
      <description>&lt;p&gt;AI conversations in the Salesforce world tend to orbit around models, features, and integrations. But working admins usually ask a much more practical question: what can I actually use AI for, day to day?&lt;/p&gt;

&lt;p&gt;One strong answer is Claude Code — an agentic coding assistant that works with Salesforce DX projects. You don't need to write Apex to get value from it. Here are seven admin tasks where it can take on the repetitive research, comparison, and drafting work, leaving you to make the decisions that need real Salesforce judgment.&lt;/p&gt;

&lt;p&gt;A few ground rules first: always test changes in a sandbox before touching production, and check your org's policy on AI tools reading metadata and data — anything Claude reads leaves your org for processing by the model provider (Anthropic, Amazon Bedrock, or Google Vertex AI, depending on your setup). Authenticate the Salesforce CLI against a sandbox (&lt;code&gt;sf org login web --instance-url https://test.salesforce.com&lt;/code&gt;) and run Claude Code from an SFDX project.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Audit custom fields with no detected references
&lt;/h2&gt;

&lt;p&gt;Leftover custom fields from old projects pile up. Ask Claude to retrieve custom fields on Account and Opportunity and flag those with no detected references across page layouts, Lightning record pages, field sets, list views, formulas, validation rules, Flows, Apex, email templates, report types, and your specified report folders — presented in a table, marked as review candidates, not confirmed unused.&lt;/p&gt;

&lt;p&gt;Your review step: reports are tricky, because the Metadata API doesn't support wildcard report retrieval, so Claude can only scan the folders you include. Also check outside the retrieved metadata — integrations, external reporting tools, data loads, managed packages, workflow rules, and old Process Builder automation. Confirm with the field owner before removing fields from layouts or deleting them; Salesforce offers no deactivate option for custom fields.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Generate permission set documentation
&lt;/h2&gt;

&lt;p&gt;When an org has dozens of permission sets, tracking who has what is slow. Have Claude retrieve the permission set metadata and query PermissionSetAssignment records (filtering out profile-owned sets), including permission set groups, member sets, and muting permission sets, then write a Markdown doc per set covering object permissions, system permissions, and assigned users.&lt;/p&gt;

&lt;p&gt;Your review step: spot-check a few sets — especially sensitive ones like Modify All Data and View All Data — against Setup. Remember the doc won't show complete effective access: profiles and session-based permission sets aren't included.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Review Flows for missing fault paths
&lt;/h2&gt;

&lt;p&gt;Record-triggered and screen Flows with Create, Update, Delete, or Get Records elements — or action elements — that lack fault connectors will show users ugly unhandled fault messages (and send error emails). Ask Claude to review the Flows in your project, list elements that support fault connectors but have no explicit fault path, explain the potential failure for each, and suggest an error-handling approach.&lt;/p&gt;

&lt;p&gt;Your review step: decide which recommendations fit your org's error-handling standards, then build and test both success and failure scenarios in a sandbox.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Draft validation rules from business requirements
&lt;/h2&gt;

&lt;p&gt;Stakeholders speak plain English; validation rules need formulas. Ask Claude to draft the rule — formula, error message, and error location — from a requirement like "prevent closing an Opportunity as Closed Won unless Amount is greater than zero and a primary contact is set, with a custom-permission bypass."&lt;/p&gt;

&lt;p&gt;Your review step: verify API names against your org. If you're checking for a primary contact, Opportunity's standard ContactId field (the ID of the contact marked Primary in Opportunity Contact Roles) may do the job without a new lookup field — though validation rules can't directly query Opportunity Contact Role records. Test valid, invalid, and bulk scenarios, including data loads and integrations, and use a custom permission rather than a profile for the bypass.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Compare metadata between sandbox and production
&lt;/h2&gt;

&lt;p&gt;Environments drift. Ask Claude to retrieve the same package.xml manifest from sandbox and production into separate folders, compare them, summarize the differences, and flag anything that exists only in production.&lt;/p&gt;

&lt;p&gt;Your review step: the comparison only covers what's in your manifest. Components that exist only in production might be direct hotfixes, managed-package content, or Salesforce features — bring genuine production changes back into the sandbox or source control before deploying so you don't overwrite them.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Write SOQL queries for data cleanup reports
&lt;/h2&gt;

&lt;p&gt;Standard reports don't always answer data-quality questions. Ask Claude to write and run a SOQL query — e.g., Contacts created in the last 90 days with no email and no recorded activity (using LastActivityDate), exported to CSV.&lt;/p&gt;

&lt;p&gt;Your review step: cross-check the record count with a quick Salesforce report, confirm your org's activity data before treating results as final, and remember query results sent to the AI tool leave your org — avoid sensitive fields unless your policy allows.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Prepare deployment packages with a change summary
&lt;/h2&gt;

&lt;p&gt;Release documentation eats time. Ask Claude to identify the week's changed components from Git history, build a package.xml manifest, run a validation-only deployment against production (&lt;code&gt;sf project deploy validate&lt;/code&gt;), and write a plain-language release summary for business users.&lt;/p&gt;

&lt;p&gt;Your review step: source tracking and Git history only go so far — provide the component list yourself when they don't. Review the summary from a business user's perspective, and be careful with permission sets: a deployment must include full permission set metadata (API 40.0+) to avoid overwriting permissions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Claude Code won't replace admin judgment — but it can absorb the repetitive research, comparison, querying, and drafting work while you focus on the decisions that genuinely need your Salesforce expertise. Pick one task from this list, try it in a sandbox, review the output, and expand from there.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://way2force.com/7-salesforce-admin-tasks-to-delegate-to-claude-code/" rel="noopener noreferrer"&gt;Originally published at Way2Force&lt;/a&gt;&lt;/p&gt;

</description>
      <category>salesforce</category>
      <category>ai</category>
      <category>tutorial</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Salesforce Flow Run Context, Explained: User vs System Context</title>
      <dc:creator>Rohan Mehta</dc:creator>
      <pubDate>Tue, 06 Oct 2026 11:46:14 +0000</pubDate>
      <link>https://dev.to/rohanmehta/salesforce-flow-run-context-explained-user-vs-system-context-2di7</link>
      <guid>https://dev.to/rohanmehta/salesforce-flow-run-context-explained-user-vs-system-context-2di7</guid>
      <description>&lt;p&gt;Every Salesforce flow runs &lt;em&gt;as someone&lt;/em&gt;. Most days you never think about it — the flow just works. Then a screen flow that behaves perfectly for you throws "insufficient privileges" for a sales rep, or an autolaunched flow quietly updates records a user was never meant to touch. That is run context at work: the set of permissions your flow borrows while it executes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The two worlds: user context vs system context
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;User context&lt;/strong&gt; means the flow runs with the launching user's permissions. Object access, field-level security, sharing rules, the role hierarchy — all enforced exactly as if the user were clicking through the records themselves. If the user cannot see a field, the flow cannot read it either.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;System context&lt;/strong&gt; means the flow bypasses the user's object and field permissions. It comes in two flavors: &lt;em&gt;with sharing&lt;/em&gt; still respects record sharing rules and the role hierarchy, while &lt;em&gt;without sharing&lt;/em&gt; removes even those guardrails — the flow can touch any record in the org.&lt;/p&gt;

&lt;p&gt;Each launch method ships with a default. Screen flows launched from a Lightning page run in user context; record-triggered and schedule-triggered flows run in system context without sharing. And flows can inherit elevated access from the flow that called them — context flows downhill.&lt;/p&gt;

&lt;h2&gt;
  
  
  The four options in Flow Builder
&lt;/h2&gt;

&lt;p&gt;On newer API versions (v68.0 and later) you get explicit control over this for screen and autolaunched flows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;User or System Context&lt;/strong&gt; — let the launch method decide (the default behavior).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User Context – Enforces User Permissions&lt;/strong&gt; — always the user's access, even when a system-context flow calls this one. Use it when a flow must never gain elevated access.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;System Context with Sharing&lt;/strong&gt; — ignores object and field permissions, but respects sharing rules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;System Context without Sharing&lt;/strong&gt; — no object, field, or record-sharing restrictions at all.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Setting it takes ten seconds: open the flow in Flow Builder, click &lt;strong&gt;View Properties&lt;/strong&gt;, then &lt;strong&gt;Show Advanced&lt;/strong&gt;, and under &lt;strong&gt;How to Run the Flow&lt;/strong&gt; pick your context and save. If the dropdown is greyed out, that flow type does not support changing run context.&lt;/p&gt;

&lt;p&gt;You will need the Manage Flow permission to touch these settings (it covers flows that use Einstein and Agentforce for Flow as well).&lt;/p&gt;

&lt;h2&gt;
  
  
  Gotchas worth knowing
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Experience Cloud is the danger zone.&lt;/strong&gt; A screen flow running in system context on a public or community site can expose internal data to external users. Default to user context there unless you have a very specific reason not to.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Some elements ignore your choice.&lt;/strong&gt; Lightning screen components and local actions always execute in user context. The Post to Chatter action always runs in user context too.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Apex can rewrite the picture.&lt;/strong&gt; Flows launched from Apex may bypass object and field permissions depending on the calling code's sharing declaration — &lt;code&gt;with sharing&lt;/code&gt; versus &lt;code&gt;without sharing&lt;/code&gt; on the class still matters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Watch inherited context.&lt;/strong&gt; When a system-context autolaunched flow launches a subflow, the subflow can inherit that elevated access. Trace the chain before you assume the user context applies.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The bottom line
&lt;/h2&gt;

&lt;p&gt;Run context is a security decision wearing an admin setting's clothes. Default to user context when the flow acts &lt;em&gt;for&lt;/em&gt; a specific person; reach for system context only when the flow needs data the user legitimately cannot reach — and prefer &lt;em&gt;with sharing&lt;/em&gt; over &lt;em&gt;without sharing&lt;/em&gt; when you do. Set it deliberately once, and you will never debug a phantom permissions error at midnight again.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://way2force.com/how-to-set-the-run-context-of-a-salesforce-flow/" rel="noopener noreferrer"&gt;Way2Force&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>salesforce</category>
      <category>flow</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
