The Wiert Corner – irregular stream of stuff

Jeroen W. Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My badges

  • Twitter Updates

  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 1,854 other subscribers

Forcing the queue on individual email message

Posted by jpluimers on 2020/11/23

I tried the trick from [WayBack] Forcing the queue on individual email message. Despite what the linked post says, on my system, the email is not sent, but bounces, and the queue files get lost, so there is no way to get to the original content without a proper back-up mechanism (which – for transient data like queued email messages – often is not implemented).

The reason is the -oTnow parameter. It is kind of documented, but none of that is returned via the “sendmail” “-oTnow” – Google Search.

Before explaining the cause and workaround deeper, these are the relevant documentation parts:

I could not find the 8.15 operations guide as PDF, but the version 8.12 HTML edition is mostly the same as the PDF (Despite the time span between those releases spanning 14 years, parameters and configuration options didn’t change a whole lot), so as the HTML is easier to quote, here we go:

The arguments; -q, -o versus -O options

[WayBack] www.sendmail.org/~ca/email/doc8.12/op-sh-7.html “ACKNOWLEDGEMENTS” explains the basic arguments as well:

Arguments must be presented with flags before addresses. The flags are:

-oxvalue
Set option x to the specified value. These options are described in Section 5.6.
-Ooption=value
Set option to the specified value (for long form option names). These options are described in Section 5.6.

-q[!]Xstring
Run the queue once, limiting the jobs to those matching Xstring. The key letter X can be I to limit based on queue identifier, R to limit based on recipient, or S to limit based on sender. A particular queued job is accepted if one of the corresponding addresses contains the indicated string. The optional ! character negates the condition tested. Multiple -qX flags are permitted, with items with the same key letter or'ed together, and items with different key letters and'ed together.

[WayBackwww.sendmail.org/~ca/email/doc8.12/op-sh-5.html “THE WHOLE SCOOP ON THE CONFIGURATION FILE” goes into more detail:

O — Set Option

There are a number of global options that can be set from a configuration file. Options are represented by full words; some are also representable as single characters for back compatibility. The syntax of this line is:

O option = value

This sets option option to be value. Note that there must be a space between the letter `O’ and the name of the option. An older version is:

O ovalue

where the option o is a single character. Depending on the option, value may be a string, an integer, a boolean (with legal values tTf, or F; the default is TRUE), or a time interval.

then lists the relevant options for us:

QueueTimeout=timeout
[T] A synonym for Timeout.queuereturn. Use that form instead of the QueueTimeout form.

Timeout.type=timeout
[r; subsumes old T option as well] Set timeout values. For more information, see section

The -oT parameter, or T option sets timeouts

[WayBack] www.sendmail.org/~ca/email/doc8.12/op-sh-4.html “TUNING” has a whole section on

Timeouts

All time intervals are set using a scaled syntax. For example, 10m represents ten minutes, whereas 2h30m represents two and a half hours. The full set of scales is:

s seconds
m minutes
h hours
d days
w weeks

There is also a special timeout value now, and timeouts can be defined in various levels, including message timeouts:

Message timeouts

After sitting in the queue for a few days, an undeliverable message will time out. This is to insure that at least the sender is aware of the inability to send a message. The timeout is typically set to five days. It is sometimes considered convenient to also send a warning message if the message is in the queue longer than a few hours (assuming you normally have good connectivity; if your messages normally took several hours to send you wouldn’t want to do this because it wouldn’t be an unusual event). These timeouts are set using the Timeout.queuereturn and Timeout.queuewarn options in the configuration file (previously both were set using the T option).

If the message is submitted using the NOTIFY SMTP extension, warning messages will only be sent if NOTIFY=DELAY is specified. The queuereturn and queuewarn timeouts can be further qualified with a tag based on the Precedence: field in the message; they must be one of urgent (indicating a positive non-zero precedence) normal (indicating a zero precedence), or non-urgent (indicating negative precedences). For example, setting Timeout.queuewarn.urgent=1h sets the warning timeout for urgent messages only to one hour. The default if no precedence is indicated is to set the timeout for all precedences. The value “now” can be used for -O Timeout.queuereturn to return entries immediately during a queue run, e.g., to bounce messages independent of their time in the queue.

Since these options are global, and since you cannot know a priori how long another host outside your domain will be down, a five day timeout is recommended. This allows a recipient to fix the problem even if it occurs at the beginning of a long weekend. RFC 1123 section 5.3.1.1 says that this parameter should be “at least 4-5 days”.

The Timeout.queuewarn value can be piggybacked on the T option by indicating a time after which a warning message should be sent; the two timeouts are separated by a slash. For example, the line

OT5d/4h

causes email to fail after five days, but a warning message will be sent after four hours. This should be large enough that the message will have been tried several times.

So the -oT is the T option, which is shorthand for -oTimeout.queuereturn. (well, actually you can combine Timeout.queuewarn using a slash).

Specifying now gives you this behaviour: The value “now” can be used for -O Timeout.queuereturn to return entries immediately during a queue run, e.g., to bounce messages independent of their time in the queue.

Of course that bounces, invalidating the below -oTnow trick.

The -qI parameter, or I queue flag for message identifier

You can also limit the jobs to those with a particular queue identifier, recipient, sender, or queue group using one of the queue modifiers. For example, -qRberkeley restricts the queue run to jobs that have the string berkeley somewhere in one of the recipient addresses. Similarly, -qSstring limits the run to particular senders, -qIstring limits it to particular queue identifiers, and -qGstring limits it to a particular queue group. You may also place an ! before the I or R or S to indicate that jobs are limited to not including a particular queue identifier, recipient or sender. For example, -q!Rseattle limits the queue run to jobs that do not have the stringseattle somewhere in one of the recipient addresses. Should you need to terminate the queue jobs currently active then a SIGTERM to the parent of the process (or processes) will cleanly stop the jobs.

So the -qI flag followed by an identifier only processes that message.

Sending to a host that got marked as timeout: the Timeout.hoststatus option

When sending just one message, you definitely want to disregard any cached host timeout status: you want to retry the message now, not skip it just because the host had a timeout a while ago.

This is where the -OTimeout.hoststatus=0m comes in: it sets the cache to zero minutes.

Below are the relevant bits of documentation.

[WayBack] cf/m4/README.txt:

confTO_HOSTSTATUS  Timeout.hoststatus
                    [30m] How long information about host
                    statuses will be maintained before it
                    is considered stale and the host should
                    be retried.  This applies both within
                    a single queue run and to persistent
                    information (see below).
...
confHOST_STATUS_DIRECTORY HostStatusDirectory
                    [undefined] If set, host status is kept
                    on disk between sendmail runs in the
                    named directory tree.  This need not be
                    a full pathname, in which case it is
                    interpreted relative to the queue
                    directory.

[WayBack] chapter 4 “TUNING”

Read timeouts

Timeouts all have option names Timeout.suboption. Most of these control SMTP operations. The recognized suboptions, their default values, and the minimum values allowed by RFC 2821 section 4.5.3.2 (or RFC 1123 section 5.3.2) are:

hoststatus
How long status information about a host (e.g., host down) will be cached before it is considered stale [30m, unspecified].

A trick that really works

With the above information,

sendmail -v -OTimeout.hoststatus=0m -qImessage_identifier

So it is now a bash function for me: sendmail-retry-one-messae-by-queue-ID:

function sendmail-retry-one-messae-by-queue-ID() {
  sendmail -v -OTimeout.hoststatus=0m -qI$1                     
}

Back to the original “trick” (that makes you loose the message)

I made it into a function:

function sendmail-bounce-one-message-by-queue-ID() {
  sendmail -oTnow -qI$1
}

From [WayBack] Forcing the queue on individual email message:

comp.mail.sendmail

Paul Aviles wrote:

> I know about sendmail -q, but is is possible to individually kill a 
> pending queued email or force it with or without an NDA?

This is simple. Use the mailq command to find the local queue ID of the message. It will look something like:

      k5PBASdd010482

You can then flush the message with:

      sendmail -qIyourqueueID -oTnow

The “I” flag to the -q flag specifies which queue ID to use. The -oTnow flag sets the queue timeout to “now”. Note sendmail will still try to deliver the message once when you do this. If this is not OK, then blow the message away with:

      rm /var/spool/mqueue/*yourqueueID

But the timeout is much recommended over blowing the message away.

Just another “Harker’s Helpful Hints”

RLH

–jeroen

Posted in *nix, *nix-tools, Power User, sendmail | Leave a Comment »

Adreswijziging belastingdienst voor bewindvoering natuurlijk persoon (beschermingsbewind)

Posted by jpluimers on 2020/11/20

De belastingdienst noemt de bewindvoering van een natuurlijk persoon op een natuurlijk persoon beschermingsbewind.

Dat was initieel een beetje verwarrend (omdat je de uitleg van die term nergens op de site van de belastingdienst kunt terugvinden), maar daardoor werd wel duidelijk wat het juiste formulier is om in te sturen:

[Wayback] www.belastingdienst.nl/wps/wcm/connect/bldcontentnl/themaoverstijgend/programmas_en_formulieren/aanmelden_wijzigen_of_beeindigen_beschermingsbewind

Insturen kon per e-mail: reuze handig!

Meer info:

Read the rest of this entry »

Posted in About, Curatele, LifeHacker, Personal, Power User | Leave a Comment »

(German): the mid 1980s stories of calling Peter Norton for free from a German phone booth, and hacking the phone lines that mobile telecom equipment sales vans connected to.

Posted by jpluimers on 2020/11/20

Two great German stories from the mid 1980s posted mid 2020.

They translate fine in Google, so enjoy!

Read the rest of this entry »

Posted in dial-up modems, History, Power User | Leave a Comment »

Meldingen over foutparkeren in Amsterdam buiten kantoor-uren: bellen naar 14020 of via https://web.archive.org/web/20181224135325/https:/twitter.com/webcare020/status/1077198930876788737

Posted by jpluimers on 2020/11/20

[WayBack] Webcare Amsterdam on Twitter : “Hee Jeroen, jammer dat de auto nu al weg is. Mocht je in het weekend weer een melding willen doen dan kan dat via 14020 of via meldingen.amsterdam.nl. Fijne feestdagen toegewenst! ^TR…”

Buiten kantoortijden melden van foutparkeerders:

–jeroen

Read the rest of this entry »

Posted in LifeHacker, Power User | Leave a Comment »

Kristian Köhntopp had an interesting JOINs go when moving from monolithic to microservicecs (i.e. when customers and orders are in separate services)

Posted by jpluimers on 2020/11/19

https://twitter.com/isotopp/status/1270824610469208072

is a summary of:

[WayBack] Thread by @isotopp: Are you a Developer and understand (Micro-) Services? I am a database person and a bit simple, and I have a genuine Question: When moving to…

Are you a Developer and understand (Micro-) Services? I am a database person and a bit simple, and I have a genuine Question:

When moving to a services architecture, where do the JOINs go?

So you sell stuff, that is you have an orders table o, with an oid, which stores a customer id cid from a customers c table, and an article id aid, from an articles table and a count cnt.
customer 17 ordered 3 45’s:
? SELECT cnt
> FROM o JOIN c ON o.cid = c.cid
> AND o.aid = a.aid
> WHERE c.cid = 17;= 3
When moving to services, because you are multibillion dollar enterprise, your customers, orders and articles can no longer fit into a single database, and there are other reasons to have an OrderService, CustomerService and ArticleService.

You still want to ask something (OrderService?) about the number of 45’s that 17 ordered.

Who do you ask? What does this do to connect the dots? How do you do reporting (“Show me all top 10 articles by country, zipcode digit 1 by week over the last 52w”)?

Do you reimplement join algorithms by hand in application code? Are there supporting tools? Do you reimplement data warehousing aggregations, too?
If so, what tooling for reporting does exist, and how does that compare to eg existing tooling for data warehousing?

Some of the reactions on Twitter are below

–jeroen

Read the rest of this entry »

Posted in Database Development, Development, Software Development, Systems Architecture | Leave a Comment »

960 Grid System

Posted by jpluimers on 2020/11/19

Would this be the reason that so many web-sites still use less than half of my screen width?

The 960 Grid System is an effort to streamline web development workflow.

Source: [WayBack] 960 Grid System

Via: [WayBack] windows – What minimum screen size should I assume? – Stack Overflow (where in 2010 for some types of software you had to go for 640×480, many things were still 800×600, but 1024×768 for desktop users was the norm; on the one hand times have changed, but on the other hand not a lot).

Code: [WayBack] GitHub – nathansmith/960-Grid-System: The 960 Grid System is an effort to streamline web development workflow.

Related:

–jeroen

Posted in Development, Software Development, Usability, User Experience (ux), Web Development | Leave a Comment »

A bunch of Spring4D dependency injection container related questions

Posted by jpluimers on 2020/11/19

Since G+ is down, a lot of interesting questions have vanished.

Luckily I saved some by [WayBack] Jacek Laskowski – Google+ related to Spring4D and dependency injection:

[WayBack] Spring4D IoC and specific singleton… – Jacek Laskowski – Google+

First my Google Groups archival reminder:

  1. Rename from
  2. To
  3. Save that URL with Archive.is

Read the rest of this entry »

Posted in Conference Topics, Conferences, Delphi, Development, Event, Software Development | Leave a Comment »

Checkout github pull requests locally · GitHub

Posted by jpluimers on 2020/11/18

Checkout github pull requests locally. GitHub Gist: instantly share code, notes, and snippets.

Source: [WayBack] Checkout github pull requests locally · GitHub

The trick is to add one more fetch line to the [remote "origin"] sections in your .git/config files, as in the gist below.

fetch = +refs/pull/*/head:refs/remotes/origin/pr/*

Which reminds me I should read more about that the fetch syntax which is called RefSpec: [WayBack] Git – The Refspec

–jeroen

Read the rest of this entry »

Posted in Development, DVCS - Distributed Version Control, git, GitHub, Software Development, Source Code Management | Leave a Comment »

Do not make methods protected unless you want them to be visible as public

Posted by jpluimers on 2020/11/18

One of the protection levels in Delphi is protected. Originally meant for the class itself, that level is also visible to “friends”: anything in the same unit, for example:

unit BusinessLogicUnit;

interface

type
  TBusinessLogic = class(TObject)
  protected
     Procedure Foo();
     // ...
  public
     // ...
  end;

implementation

// ...

end.

You can even access them from outside that unit by using a trick like below.

Some people use the protected section so that unit tests can assess them using the below trick.

Do not do that!

It means anyone can use that trick, often doing more damage than good.

In this case, the trick was abused by a clever programmer that was relatively new to the code base. It resulted in unintended side effects.

unit HackUnit;

interface

implementation

uses
  BusinessLogicUnit;

type
  TBusinessLogicHack = class(TBusinessLogic);

procedure Hack;
var
  Instance: TBusinessLogicHack;
begin
  Instance := TBusinessLogicHack.Create();
  try
    Instance.Foo();
  finally
    Instance.Free();
  end;
end;

end.

Of course you can still access it like below.

It is slightly longer, but more importantly: much better shows the intent and how that intent is accomplished.

unit GoodUsageUnit;

interface

implementation

uses
  BusinessLogicUnit;

type
  TBusinessLogicDescendant = class(TBusinessLogic)
  public
    procedure Foo();
  end;

procedure TBusinessLogicDescendant.Foo();
begin
  inherited Foo();
  // ...
end;

procedure Usage;
var
  Instance: TBusinessLogicDescendant;
begin
  Instance := TBusinessLogicDescendant.Create();
  try
    Instance.Foo();
  finally
    Instance.Free();
  end;
end;

end.

–jeroen

Posted in Conference Topics, Conferences, Delphi, Development, Event, Software Development | 1 Comment »

The Delphi Geek: Using Generics to Manipulate Enumerated Types

Posted by jpluimers on 2020/11/18

Not that this is bad code, but there are no unit tests for them, and I have seen places in the wild that blindly use it without documenting where it came from and what tested alternatives might be: [WayBack] The Delphi Geek: Using Generics to Manipulate Enumerated Types

The unit itself is down (though there is still a copy on the WayBack machine).

The post itself mentions it is Spring4D-inspired, and since Spring4D already has quite an extensive [WayBack] TEnum<T> implementation covered by unit tests, so that is a logical place to do for.

I might actually document the migration table if I find time for it.

Here is a start so I will only have to insert the blanks

Function Replacement
class function Clip(const value: Integer): T;
class function Clip(const value: T): T;
class function Ensure(const value: Integer; const min, max: T): T;
class function Ensure(const value, min, max: T): T;
class function FromInt(const value: Integer): T;
class function Enum: RangeEnum; static;
class function GetValueOrDefault(const value: Integer): T;
class function IsValid(const value: Integer): Boolean;
class function IsValid(const value: T): Boolean;
class function Max: T; static;
class function Min: T; static;
class function ToInt(const value: T): Integer;
class function ToString(const value: T): string;

–jeroen

Posted in Delphi, Development, Software Development | Leave a Comment »